package com.ld.shieldsb.common.web;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.ld.shieldsb.annotation.field.db.OnlyShow;
import com.ld.shieldsb.annotation.field.link.Link;
import com.ld.shieldsb.annotation.field.link.Many2Many;
import com.ld.shieldsb.annotation.util.AnnotationUtil;
import com.ld.shieldsb.common.composition.util.PKUtil;
import com.ld.shieldsb.common.composition.util.web.Global;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.io.IOUtils;
import com.ld.shieldsb.common.core.model.Description;
import com.ld.shieldsb.common.core.model.PropertiesModel;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.reflect.ClassUtil;
import com.ld.shieldsb.common.core.reflect.FunctionUtil;
import com.ld.shieldsb.common.core.reflect.FunctionUtil.Property;
import com.ld.shieldsb.common.core.reflect.ModelUtil;
import com.ld.shieldsb.common.core.util.ResultUtil;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.web.annotation.DB.DataSource;
import com.ld.shieldsb.common.web.model.SysUser;
import com.ld.shieldsb.common.web.util.Web;
import com.ld.shieldsb.dao.TransactionImplBaseDao;
import com.ld.shieldsb.dao.TransactionManager;
import com.ld.shieldsb.dao.model.PageNavigationBean;
import com.ld.shieldsb.dao.model.QueryModel;
import com.ld.shieldsb.dao.util.LogUtil;
import com.ld.shieldsb.db.dao.dynamic.DynamicBaseDao;
import com.ld.shieldsb.db.model.DBSetInfo;
import com.ld.shieldsb.db.service.DBTabelService;

/**
 * mysql数据库的service，oracle等其他库需要自己实现
 *
 * @ClassName BasicService
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年3月12日 下午3:15:57
 *
 */
@DataSource("") // 数据源注解，不写默认继承父类
@Service
public class BasicService {
    protected static final Logger log = LoggerFactory.getLogger(BasicService.class);
    private TransactionImplBaseDao BaseDAO = null; // 不可static会被子类覆盖
    public String defaultDataSource = "db0."; // 默认值
    protected String adminPath = Global.PROJECT_ADMIN_S;
    protected String frontPath = Global.PROJECT_FRONT_S;

    protected Boolean queryLink = true; // 查询级联对象,先判断此属性此属性为true时再判断QueryModel中的queryLink

    protected Class<? extends SysUser> userCls = SysUser.class; // 用户类，可能被子项目覆盖所以此处做成变量可覆盖

//    private static final Class<?> getCurrentClass() {
//
//        return new Object() {
//            public Class<?> getClassForStatic() {
//                return this.getClass();
//            }
//        }.getClassForStatic();
//    }

    public BasicService() {
        super();
        init();
    }

    public void init() {
    }

    @Autowired
    public HttpServletResponse response;
    @Autowired
    public HttpServletRequest request;
    @Autowired
    public HttpSession session;

    public static final int PAGE_SIZE = 20;

    public int getInt(String name) {
        return Web.Parameter.getInt(request, name);
    }

    public long getLong(String name) {
        return Web.Parameter.getLong(request, name);
    }

    public String getString(String name) {
        return Web.Parameter.getString(request, name);
    }

    public double getDouble(String name) {
        return Web.Parameter.getDouble(request, name);
    }

    public Date getDate(String name) {
        return Web.Parameter.getDate(request, name);
    }

    /**
     * 根据参数名，返回参数list
     *
     * @Title getList
     * @author 吕凯
     * @date 2017年3月3日 下午2:27:10
     * @param name
     * @return List<String>
     */
    protected List<String> getList(String name) {
        return Web.Parameter.getList(request, name);
    }

    /**
     *
     * 根据参数名，返回参数set
     *
     * @Title getSet
     * @author 吕凯
     * @date 2017年3月3日 下午3:04:23
     * @param name
     * @return Set<String>
     */
    protected Set<String> getSet(String name) {
        return Web.Parameter.getSet(request, name);
    }

    /**
     *
     * 将list对象设置到request中,参数名默认list
     *
     * @Title setRequestAttriList
     * @author 吕凯
     * @date 2018年6月25日 下午12:27:54
     * @param request
     * @param list
     *            void
     */
    public void setRequestAttriList(HttpServletRequest request, List<?> list) {
        setRequestAttriList(request, list, null);

    }

    /**
     *
     * 将list对象设置到request中
     *
     * @Title setRequestAttriList
     * @author 吕凯
     * @date 2018年6月25日 下午12:27:14
     * @param request
     * @param list
     * @param attrName
     *            void
     */
    public void setRequestAttriList(HttpServletRequest request, List<?> list, String attrName) {
        if (request != null) {
            if (StringUtils.isNotBlank(attrName)) {
                request.setAttribute(attrName, list); // list
            } else {
                request.setAttribute("list", list); // list
            }
        }

    }

    /**
     *
     * 将对象设置到request中,参数名默认model
     *
     * @Title setRequestAttriModel
     * @author 吕凯
     * @date 2018年6月25日 下午12:26:47
     * @param request
     * @param model
     *            void
     */
    public void setRequestAttriModel(HttpServletRequest request, Object model) {
        setRequestAttriModel(request, model, null);

    }

    /**
     * 将对象设置到request中
     *
     * @Title setRequestAttriModel
     * @author 吕凯
     * @date 2018年6月25日 下午12:25:50
     * @param request
     * @param model
     * @param attrName
     *            attr名称void
     */
    public void setRequestAttriModel(HttpServletRequest request, Object model, String attrName) {
        if (request != null) {
            if (StringUtils.isNotBlank(attrName)) {
                request.setAttribute(attrName, model); // 单个对象
            } else {
                request.setAttribute("model", model); // 单个对象
            }
        }

    }

    // 获取单个对象
    public <T> T getOne(Class<T> classOfT, Long id) {
        return getOne(classOfT, "id", id);
    }

    public <T> T getOne(Class<T> classOfT, String key, Object value) {
        return getOne(null, classOfT, key, value); //
    }

    public <T> T getOne(HttpServletRequest request, Class<T> classOfT, Long id) {
        return getOne(request, classOfT, "id", id);
    }

    public <T> T getOne(HttpServletRequest request, Class<T> classOfT, String key, Object value) {
        T obj = getBaseDAO().findById(classOfT, key, value);
        QueryModel linkedQueryModel = new QueryModel();
        linkedQueryModel.setQueryLink(checkQueryModelLinkObj(request, obj));
        queryLinkFields(linkedQueryModel, obj); // 查询关联对象
        setRequestAttriModel(request, obj);
        return obj;
    }

    // 带关联对象
    public <T> T getOneAndLinks(Class<T> classOfT, Long id) {
        return getOneAndLinks(null, classOfT, "id", id);
    }

    public <T> T getOneAndLinks(HttpServletRequest request, Class<T> classOfT, Long id) {
        return getOneAndLinks(request, classOfT, "id", id);
    }

    /**
     * 获取对象及级联对象
     *
     * @Title getOneAndLinks
     * @author 吕凯
     * @date 2019年8月6日 上午8:32:26
     * @param request
     * @param classOfT
     * @param key
     * @param value
     * @return T
     */
    public <T> T getOneAndLinks(HttpServletRequest request, Class<T> classOfT, String key, Object value) {
        T obj = getBaseDAO().findById(classOfT, key, value);
        QueryModel linkedQueryModel = getNormalQueryModel();
        linkedQueryModel.setQueryLink(true);
        queryLinkFields(linkedQueryModel, obj); // 查询关联对象
        setRequestAttriModel(request, obj);
        return obj;
    }

    public <T> T getOneAndLinks(Class<T> classOfT, String key, Object value) {
        return getOneAndLinks(null, classOfT, key, value);
    }

    /**
     * 获取正常对象
     * 
     * @Title getNormalOne
     * @author 吕凯
     * @date 2021年1月28日 上午11:00:05
     * @param <T>
     * @param classOfT
     * @param id
     * @return T
     */
    public <T> T getNormalOne(Class<T> classOfT, Long id) {
        return getNormalOne(classOfT, id, null);
    }

    public <T> T getNormalOne(Class<T> classOfT, String key, Object value) {
        return getNormalOne(null, classOfT, key, value, null);
    }

    public <T> T getNormalOne(Class<T> classOfT, Long id, String selectFields) {
        return getNormalOne(null, classOfT, id, selectFields);
    }

    public <T> T getNormalOne(HttpServletRequest request, Class<T> classOfT, Long id) {
        return getNormalOne(request, classOfT, id, null);
    }

    public <T> T getNormalOne(HttpServletRequest request, Class<T> classOfT, Long id, String selectFields) {
        return getNormalOne(request, classOfT, "id", id, selectFields);
    }

    public <T> T getNormalOne(HttpServletRequest request, Class<T> classOfT, String key, Object value) {
        return getNormalOne(request, classOfT, key, value, null);
    }

    public <T> T getNormalOne(HttpServletRequest request, Class<T> classOfT, String key, Object value, String selectFields) {
        QueryModel queryModel = getNormalQueryModel(selectFields);
        queryModel.addEq(key, value);
        return getOne(request, classOfT, queryModel);
    }

    public <T> T getOne(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        T obj = getOne(classOfT, queryModel);
        setRequestAttriModel(request, obj);
        return obj;
    }

    public <T> T getOne(Class<T> classOfT, QueryModel queryModel) {
        T obj = getBaseDAO().getOne(classOfT, queryModel);
        QueryModel linkedQueryModel = getNormalQueryModel();
        linkedQueryModel.setQueryLink(queryModel.getQueryLink());
        linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields());
        queryLinkFields(linkedQueryModel, obj); // 查询关联对象
        return obj;
    }

    public <T> T getOne(Class<T> classOfT, QueryModel queryModel, QueryModel linkedQueryModel) {
        T obj = getBaseDAO().getOne(classOfT, queryModel);
        queryLinkFields(linkedQueryModel, obj); // 查询关联对象
        return obj;
    }

    /**
     * @Description 获取对象及级联对象 将对象放入request中 传递页面使用
     * @Author 付信豪
     * @Date 2020/7/9 8:10
     * @ModifyDate 2020/7/9 8:10
     * @Params [request, classOfT, queryModel]
     * @Return T
     */

    public <T> T getOne(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, QueryModel linkedQueryModel) {
        T obj = getBaseDAO().getOne(classOfT, queryModel);
        queryLinkFields(linkedQueryModel, obj); // 查询关联对象
        setRequestAttriModel(request, obj);
        return obj;
    }

    /**
     * 获取对象及级联对象
     *
     * @Title getOneAndLinks
     * @author 吕凯
     * @date 2019年8月6日 上午8:30:50
     * @param classOfT
     * @param queryModel
     * @return T
     */
    public <T> T getOneAndLinks(Class<T> classOfT, QueryModel queryModel) {
        queryModel.setQueryLink(true);
        return getOne(classOfT, queryModel);
    }

    public <T> T getOneAndLinks(Class<T> classOfT, QueryModel queryModel, QueryModel linkedQueryModel) {
        linkedQueryModel.setQueryLink(true);
        return getOne(classOfT, queryModel, linkedQueryModel);
    }

    /**
     * @Description 获取对象及级联对象 并将对象放入request中 传递页面使用
     * @Author 付信豪
     * @Date 2020/7/9 8:10
     * @ModifyDate 2020/7/9 8:10
     * @Params [request, classOfT, queryModel]
     * @Return T
     */
    public <T> T getOneAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        queryModel.setQueryLink(true);
        return getOne(request, classOfT, queryModel);
    }

    public <T> T getOneAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, QueryModel linkedQueryModel) {
        linkedQueryModel.setQueryLink(true);
        return getOne(request, classOfT, queryModel, linkedQueryModel);
    }

    /**
     * 检查是否查询单个对象的关联对象（通过queryModel）
     *
     * @Title checkQueryModelLinkObj
     * @author 吕凯
     * @date 2019年7月26日 上午8:28:32
     * @param queryModel
     * @param obj
     * @return boolean
     */
    private <T> boolean checkQueryModelLinkObj(QueryModel queryModel, T obj) {
        return obj != null && queryLink && queryModel.getQueryLink() != null && queryModel.getQueryLink();
    }

    /**
     *
     * 检查是否查询单个对象的关联对象（通过request的Web.Attr.REQUEST_ATTR_QUERYLINK）
     *
     * @Title checkQueryModelLinkObj
     * @author 吕凯
     * @date 2019年7月26日 上午8:31:12
     * @param request
     * @param obj
     * @return boolean
     */
    private <T> boolean checkQueryModelLinkObj(HttpServletRequest request, T obj) {
        Boolean queryObjLink = false;
        if (obj != null && this.queryLink) {
            try {
                if (request != null) { // request不传时，默认可查询
                    queryObjLink = (Boolean) request.getAttribute(Web.Attr.REQUEST_ATTR_QUERYLINK); // 查询关联
                }
            } catch (Exception e) {
                log.error("", e);
            }
            if (queryObjLink == null) { // 默认不查询
                queryObjLink = false;
            }
        }
        return queryObjLink;
    }

    public <T> Long getCount(Class<T> classOfT, QueryModel queryModel) {
        return getBaseDAO().getCount(classOfT, queryModel);
    }

    // 获取List对象
    public <T> List<T> getNormalList(Class<T> classOfT) {
        return getNormalList(classOfT, new QueryModel());
    }

    public <T> List<T> getNormalList(Class<T> classOfT, QueryModel queryModel) {
        queryModel.addEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_NORMAL);
        return getList(classOfT, queryModel);
    }

    public <T> List<T> getList(Class<T> classOfT, QueryModel queryModel) {
        QueryModel linkedQueryModel = getNormalQueryModel();
        linkedQueryModel.setQueryLink(queryModel.getQueryLink());
        return getList(classOfT, queryModel, linkedQueryModel);
    }

    public <T> List<T> getList(Class<T> classOfT, QueryModel queryModel, QueryModel... linkedQueryModels) {
        List<T> list = getBaseDAO().getList(classOfT, queryModel);

        // 查询关联对象
        long time1 = System.currentTimeMillis();
//        QueryModel linkedQueryModel = getNormalQueryModel();
//        linkedQueryModel.setQueryLink(queryModel.getQueryLink());
//        linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields());
        queryLinkFields(classOfT, list, queryModel, linkedQueryModels);
//        queryLinkFields2(classOfT, queryModel, list); // 对比
        long time2 = System.currentTimeMillis();
        log.debug("time2-time1=" + (time2 - time1));
        return list;
    }

    /**
     * 查询list及级联对象
     *
     * @Title getListAndLinks
     * @author 吕凯
     * @date 2019年8月6日 上午8:35:05
     * @param classOfT
     * @param queryModel
     * @return List<T>
     */
    public <T> List<T> getListAndLinks(Class<T> classOfT, QueryModel queryModel) {
        // 查询关联对象
        /*
         * QueryModel linkedQueryModel = queryModel; linkedQueryModel.setQueryLink(queryModel.getQueryLink());
         * linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields());
         */

        return getListAndLinks(null, classOfT, queryModel);
    }

    public <T> List<T> getListAndLinks(Class<T> classOfT, QueryModel queryModel, QueryModel... linkedQueryModels) {
        List<T> list = getBaseDAO().getList(classOfT, queryModel);

        // 查询关联对象
        long time1 = System.currentTimeMillis();
//        QueryModel linkedQueryModel = new QueryModel();
//        linkedQueryModel.setQueryLink(queryModel.getQueryLink());
//        linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields());
        queryLinkFields(classOfT, list, queryModel, linkedQueryModels);
//        queryLinkFields2(classOfT, queryModel, list); // 对比
        long time2 = System.currentTimeMillis();
        log.warn("time2-time1=" + (time2 - time1));
        return list;
    }

    public <T> List<T> fetchLinks(List<T> list, Property<T, ?> property) {
        return fetchLinks(list, property, null, getNormalQueryModel());
    }

    /**
     * 用于手动查询list关联对象
     *
     * @Title fetchLinks
     * @author 吕凯
     * @date 2019年7月26日 下午2:29:50
     * @param list
     *            集合对象
     * @param property
     *            查询的关联对象
     * @param queryModel
     *            查询条件，注意尽量new不要传递防止参数混乱
     * @return List<T>
     */
    public <T> List<T> fetchLinks(List<T> list, Property<T, ?> property, QueryModel linkedQueryModels) {
        return fetchLinks(list, property, null, linkedQueryModels);
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> fetchLinks(List<T> list, Property<T, ?> property, QueryModel queryModel, QueryModel... linkedQueryModels) {
        // 查询关联对象
        long time1 = System.currentTimeMillis();
        if (ListUtils.isNotEmpty(list)) {
            if (queryModel == null) {
                queryModel = new QueryModel();
            }
            queryModel.setQueryLink(true);
            Class<T> classOfT = (Class<T>) list.get(0).getClass();
            queryModel.addQueryField(property);
            queryLinkFields(classOfT, list, queryModel, linkedQueryModels);
        }
        long time2 = System.currentTimeMillis();
        log.debug("time2-time1=" + (time2 - time1));
        return list;
    }

    /**
     * 用于手动查询单个对象的关联对象
     *
     * @Title fetchLinks
     * @author 吕凯
     * @date 2019年7月26日 下午4:35:03
     * @param obj
     * @param property
     * @param linkQueryModel
     *            查询条件，注意尽量new不要传递防止参数混乱
     * @return T
     */
    public <T> T fetchLinks(T obj, Property<T, ?> property, QueryModel linkQueryModel) {
        // 查询关联对象
        long time1 = System.currentTimeMillis();
        if (obj != null) {
            if (linkQueryModel == null) {
                linkQueryModel = new QueryModel();
            }
            linkQueryModel.setQueryLink(true);
            linkQueryModel.addQueryField(property);
            queryLinkFields(linkQueryModel, obj);
        }
        long time2 = System.currentTimeMillis();
        log.debug("查询关联对象耗时(毫秒)：" + (time2 - time1));
        return obj;
    }

    /**
     * 
     * 用于手动查询单个对象的关联对象
     * 
     * @Title fetchLinks
     * @author 吕凯
     * @date 2020年12月8日 下午3:18:36
     * @param <T>
     * @param obj
     * @param property
     * @return T
     */
    public <T> T fetchLinks(T obj, Property<T, ?> property) {
        return fetchLinks(obj, property, new QueryModel());
    }

    /**
     * 查询list的关联对象
     *
     * @Title queryLinkFields
     * @author 吕凯
     * @date 2019年7月24日 下午5:10:07
     * @param classOfT
     * @param queryModel
     * @param list
     *            void
     */
    private <T> void queryLinkFields(Class<T> classOfT, List<T> list, QueryModel queryModel, QueryModel... linkedQueryModels) {
        if (checkQueryListLinkObj(queryModel, list)) {
            // 注意三表查询的查询条件的传递
            secondTableRelationDeal(classOfT, list, queryModel, linkedQueryModels); // 2表关联
            thirdTableRelationDeal(classOfT, list, queryModel, linkedQueryModels); // 3表关联
        }
    }

    /**
     * 2表关联的查询
     * 
     * @Title secondTableRelationDeal
     * @author 吕凯
     * @date 2021年3月10日 上午8:58:46
     * @param <T>
     * @param classOfT
     * @param list
     * @param queryModel
     * @param linkedQueryModels
     *            void
     */
    private <T> void secondTableRelationDeal(Class<T> classOfT, List<T> list, QueryModel queryModel, QueryModel... linkedQueryModels) {
        List<Field> linkFields = getLinkFields(classOfT, queryModel);
        if (ListUtils.isNotEmpty(linkFields)) { // 存在关联字段时
            LogUtil.daoDebug("查询关联对象1=" + linkFields);
            // 1、查出list中对应关联查询属性的值，并将相同的Field组合为set放到一个Map中
            Map<Field, Set<Object>> linkFieldFromValueMap = new LinkedHashMap<>(); // 存放的是field的关联对象的值，按顺序
            List<Field> casecadeFieldNameList = new ArrayList<>(); // 多级属性
            list.forEach(model -> {
                linkFields.forEach(field -> {
                    Link link = field.getAnnotation(Link.class);
                    String linkFieldName = link.field();
                    if (linkFieldName.contains(".")) { // 多级属性
                        casecadeFieldNameList.add(field);
                    } else {
                        Object linkFieldValue = ModelUtil.getModelValue(model, linkFieldName);

                        if (linkFieldValue != null) { // 排除空值，空字符串
                            Set<Object> linkFieldValueSet = linkFieldFromValueMap.get(field);
                            if (linkFieldValueSet == null) {
                                linkFieldValueSet = new HashSet<>();
                            }
                            linkFieldValueSet.add(linkFieldValue);
                            linkFieldFromValueMap.put(field, linkFieldValueSet);
                        }
                    }
                });
            });
            // 2、上一步中针对每个Field的值Set进行查询，查询结果放到一个新的Map中
            Map<Field, List<?>> linkFieldValMap = secondTableRelationQueryFieldValues(linkFieldFromValueMap, linkedQueryModels);
            // 3、对model进行循环赋值，model中需要处理的field在list中有对象的值则赋值
            secondTableRelationSetFieldValues(list, linkFieldFromValueMap, linkFieldValMap);

            // 如果存在多级对象继续处理
            if (ListUtils.isNotEmpty(casecadeFieldNameList)) {
                Map<Field, Set<Object>> linkFieldCasecadeValueMap = new LinkedHashMap<>(); // 级联属性按顺序
                list.forEach(model -> {
                    casecadeFieldNameList.forEach(field -> {
                        Link link = field.getAnnotation(Link.class);
                        String linkFieldName = link.field();
                        Object linkFieldValue = ModelUtil.getModelValue(model, linkFieldName);

                        if (linkFieldValue != null) { // 排除空值，空字符串
                            Set<Object> linkFieldValueSet = linkFieldCasecadeValueMap.get(field);
                            if (linkFieldValueSet == null) {
                                linkFieldValueSet = new HashSet<>();
                            }
                            linkFieldValueSet.add(linkFieldValue);
                            linkFieldCasecadeValueMap.put(field, linkFieldValueSet);
                        }
                    });
                });

                // 2、上一步中针对每个Field的值Set进行查询，查询结果放到一个新的Map中
                linkFieldValMap = secondTableRelationQueryFieldValues(linkFieldCasecadeValueMap, linkedQueryModels);
                // 3、对model进行循环赋值，model中需要处理的field在list中有对象的值则赋值
                secondTableRelationSetFieldValues(list, linkFieldCasecadeValueMap, linkFieldValMap);

            }
        }
    }

    /**
     * 对list集合设置值
     * 
     * @Title secondTableRelationSetFieldValues
     * @author 吕凯
     * @date 2021年3月10日 上午10:00:51
     * @param <T>
     * @param list
     * @param linkFieldFromValueMap
     *            是field与关联对象的值的map
     * @param linkFieldValMap
     *            是field与对象真实值的map void
     */
    private <T> void secondTableRelationSetFieldValues(List<T> list, Map<Field, Set<Object>> linkFieldFromValueMap,
            Map<Field, List<?>> linkFieldValMap) {
        if (ListUtils.isNotEmpty(linkFieldFromValueMap.entrySet())) {
            list.forEach(model -> { // 3.1对list进行循环
                linkFieldValMap.keySet().forEach(field -> { // 3.2循环field，获取model中该field的值，与val对比，如果发现合适的值则赋值给model的关联对象
                    field.setAccessible(true); // 设为可访问，否则field.set(obj,val)报错
                    Link link = field.getAnnotation(Link.class);
                    String targetPK = link.targetField(); // 目标对象的主键
                    String linkFieldName = link.field();
                    Object linkFieldValue = ModelUtil.getModelValue(model, linkFieldName); // model中的值
                    if (linkFieldValue != null) {
                        List<?> fieldValList = linkFieldValMap.get(field);
                        if (ListUtils.isNotEmpty(fieldValList)) {
                            // 针对单一对象
                            Class<?> fieldType = field.getType();
                            if (fieldType.equals(List.class)) {
                                List<?> valList = new ArrayList<>();
                                setLinkModelFieldValue2Collec(model, field, targetPK, linkFieldValue, fieldValList, valList);
                            } else if (fieldType.equals(Set.class)) {
                                Set<?> valSet = new HashSet<>();
                                setLinkModelFieldValue2Collec(model, field, targetPK, linkFieldValue, fieldValList, valSet);
                            } else { // 非集合对象，直接赋值
                                fieldValList.forEach(valModel -> {
                                    Object valModelPK = ModelUtil.getModelValue(valModel, targetPK);
                                    if (valModelPK != null && valModelPK.toString().equals(linkFieldValue.toString())) { // model中的值与获取到的对象的主键相同
                                        try {
                                            field.set(model, valModel);
                                        } catch (IllegalArgumentException | IllegalAccessException e) {
                                            log.error("设置属性出错", e);
                                        }
                                    }
                                });
                            }
                        }

                    }
                });

            });
        }
    }

    /**
     * 查询list里关联对象的值到map中，还没有设置值
     * 
     * @Title secondTableRelationQueryFieldValues
     * @author 吕凯
     * @date 2021年3月10日 上午10:01:36
     * @param linkFieldValueMap
     * @param linkedQueryModels
     * @return Map<Field,List<?>>
     */
    private Map<Field, List<?>> secondTableRelationQueryFieldValues(Map<Field, Set<Object>> linkFieldValueMap,
            QueryModel... linkedQueryModels) {
        QueryModel linkQueryModelCopy = null; // 默认的查询model，用于没有设置的条件
        if (linkedQueryModels.length > 0) {
            linkQueryModelCopy = linkedQueryModels[0].copy(); // 复制关联对象防止多个关联对象直接的干扰
        } else {
            linkQueryModelCopy = new QueryModel(); // 关联对象暂不区分对象的state状态
        }
        Map<Field, List<?>> linkFieldValMap = new HashMap<>(); // 查询出来的对象的map
        if (ListUtils.isNotEmpty(linkFieldValueMap.entrySet())) {
            int index = 0;
            for (Map.Entry<Field, Set<Object>> entry : linkFieldValueMap.entrySet()) {
                Field field = entry.getKey();
                Set<Object> fieldValues = entry.getValue();

                Class<?> fieldType = ClassUtil.getFieldPojoType(field); // 获取对象的类型
                Link link = field.getAnnotation(Link.class);
                String targetPK = link.targetField(); // 目标对象的主键
                Description fieldDesc = AnnotationUtil.getFieldDescription(fieldType, targetPK);
                if (fieldDesc != null) {
                    String targetPKDB = fieldDesc.getDbName(); // 目标对象的主键对应数据库中的名字

                    String queryFields = link.queryFields();
                    if ("*".equals(queryFields)) { // 查询所有字段，看是否排除某些字段
//                        String queryFieldsExclude = link.queryFieldsExclude(); // 获取不查询的字段 TODO 暂时处理不了
                    }
                    QueryModel linkQueryModelInner = null;
                    if (linkedQueryModels.length >= index + 1) {
                        linkQueryModelInner = linkedQueryModels[index].copy();
                    } else {
                        linkQueryModelInner = linkQueryModelCopy.copy(); // 复制关联对象防止多个关联对象直接的干扰
                    }
//                    QueryModel linkQueryModel = linkedQueryModel;
//                    QueryModel linkQueryModel = new QueryModel(queryFields); // 关联对象暂不区分对象的state状态
                    // 如果queryFields不为空，并且queryModel未设置选择字段，则将该值写进去
                    if ((StringUtils.isNotEmpty(queryFields) && !"*".equals(queryFields)) // queryFields不为* 且复制的queyModel中没有设置选择字段
                            && ("*".equals(linkQueryModelInner.getSelectFields()) || "".equals(linkQueryModelInner.getSelectFields()))) {
                        linkQueryModelInner.setSelectFields(queryFields);
                    }
                    linkQueryModelInner.addInSet(targetPKDB, fieldValues);
                    List<?> linkObj = getBaseDAO().getList(fieldType, linkQueryModelInner, 1000); // 查询,限制查询1000条，TODO
                    linkFieldValMap.put(field, linkObj);
                } else {
                    log.error("关联对象的targetField属性不存在" + targetPK + "(" + fieldType + ")");
                }
                // 所以此处有问题，如果关联数据超过1000条需要自己实现
                index++;
            }
        }
        return linkFieldValMap;
    }

    /**
     * 3表关联关系的处理，多对多
     *
     * @Title thirdTableRelationDeal
     * @author 吕凯
     * @date 2019年8月31日 上午10:33:55
     * @param classOfT
     * @param queryModel
     * @param list
     *            void
     */
    private <T> void thirdTableRelationDeal(Class<T> classOfT, List<T> list, QueryModel queryModel, QueryModel... linkedQueryModels) {
        List<Field> many2manyFields = getMany2ManyFields(classOfT, queryModel);
        if (ListUtils.isNotEmpty(many2manyFields)) { // 存在关联字段时
            LogUtil.daoDebug("查询关联对象2=" + many2manyFields);
            // 1、查出list中对应关联查询属性的值，并将相同Field的组合为set放到一个Map中
            Map<Field, Set<Object>> linkFieldFromValueMap = new LinkedHashMap<>(); // 存放的是field的关联对象的值，按顺序
            List<Field> casecadeFieldNameList = new ArrayList<>(); // 多级属性
            list.forEach(model -> {
                many2manyFields.forEach(field -> {
                    Many2Many link = field.getAnnotation(Many2Many.class);
                    String fromFieldName = link.from();
                    if (fromFieldName.contains(".")) { // 多级属性
                        casecadeFieldNameList.add(field);
                    } else {
                        Object fromFieldValue = ModelUtil.getModelValue(model, fromFieldName);
                        if (fromFieldValue != null) {
                            Set<Object> linkFieldValueSet = linkFieldFromValueMap.get(field);
                            if (linkFieldValueSet == null) {
                                linkFieldValueSet = new HashSet<>();
                            }
                            linkFieldValueSet.add(fromFieldValue);
                            linkFieldFromValueMap.put(field, linkFieldValueSet);
                        }
                    }
                });
            });
            // 2、上一步中针对每个Field的值Set进行查询，查询结果放到一个新的Map中
//            Set<Field> keySet = linkFieldValueMap.keySet();
            Map<Field, List<?>> middleFieldValMap = new HashMap<>(); // 查询出来的对象的map
            Map<Field, List<?>> thirdFieldValMap = new HashMap<>(); // 查询出来的对象的map
            thirdTableRelationQueryFieldValues(queryModel, linkFieldFromValueMap, middleFieldValMap, thirdFieldValMap, linkedQueryModels);
            // 3、对model进行循环赋值，model中需要处理的field在list中有对象的值则赋值
            thirdTableRelationSetFieldValues(list, linkFieldFromValueMap, middleFieldValMap, thirdFieldValMap);

            // 如果存在多级对象继续处理
            if (ListUtils.isNotEmpty(casecadeFieldNameList)) {
                Map<Field, Set<Object>> linkFieldCasecadeValueMap = new LinkedHashMap<>(); // 级联属性按顺序
                list.forEach(model -> {
                    casecadeFieldNameList.forEach(field -> {
                        Link link = field.getAnnotation(Link.class);
                        String linkFieldName = link.field();
                        Object linkFieldValue = ModelUtil.getModelValue(model, linkFieldName);

                        if (linkFieldValue != null) { // 排除空值，空字符串
                            Set<Object> linkFieldValueSet = linkFieldCasecadeValueMap.get(field);
                            if (linkFieldValueSet == null) {
                                linkFieldValueSet = new HashSet<>();
                            }
                            linkFieldValueSet.add(linkFieldValue);
                            linkFieldCasecadeValueMap.put(field, linkFieldValueSet);
                        }
                    });
                });

                // 2、上一步中针对每个Field的值Set进行查询，查询结果放到一个新的Map中
//              Set<Field> keySet = linkFieldValueMap.keySet();
                middleFieldValMap = new HashMap<>(); // 查询出来的对象的map
                thirdFieldValMap = new HashMap<>(); // 查询出来的对象的map
                thirdTableRelationQueryFieldValues(queryModel, linkFieldCasecadeValueMap, middleFieldValMap, thirdFieldValMap,
                        linkedQueryModels);
                // 3、对model进行循环赋值，model中需要处理的field在list中有对象的值则赋值
                thirdTableRelationSetFieldValues(list, linkFieldCasecadeValueMap, middleFieldValMap, thirdFieldValMap);

            }
        }
    }

    /**
     * 
     * 对list集合设置值
     * 
     * @Title thirdTableRelationSetFieldValues
     * @author 吕凯
     * @date 2021年3月10日 上午10:24:39
     * @param <T>
     * @param list
     * @param linkFieldValueMap
     * @param middleFieldValMap
     * @param thirdFieldValMap
     *            void
     */
    private <T> void thirdTableRelationSetFieldValues(List<T> list, Map<Field, Set<Object>> linkFieldValueMap,
            Map<Field, List<?>> middleFieldValMap, Map<Field, List<?>> thirdFieldValMap) {
        if (ListUtils.isNotEmpty(linkFieldValueMap.entrySet())) {
            list.forEach(model -> { // 3.1对list进行循环（对象）
                middleFieldValMap.keySet().forEach(field -> { // 3.2循环field，获取model中该field的值，与val对比，如果发现合适的值则赋值给model的关联对象
                    field.setAccessible(true); // 设为可访问，否则field.set(obj,val)报错
                    Many2Many link = field.getAnnotation(Many2Many.class);
                    String middlFromFieldName = link.relationFrom(); // 目标对象的主键
                    String fromFieldName = link.from();
                    Object fromFieldValue = ModelUtil.getModelValue(model, fromFieldName); // model中的值
                    if (fromFieldValue != null) {
                        List<?> middleValueList = middleFieldValMap.get(field); // 中间表数据
                        List<?> thirdValueList = thirdFieldValMap.get(field); // 第三表数据
                        if (ListUtils.isNotEmpty(middleValueList) && ListUtils.isNotEmpty(thirdValueList)) {
                            // 针对单一对象
                            Class<?> fieldType = field.getType();
                            if (fieldType.equals(List.class)) {
                                List<?> valList = new ArrayList<>();
                                set3TableFieldValue2Collec(model, field, middleValueList, thirdValueList, valList);
                            } else if (fieldType.equals(Set.class)) {
                                Set<?> valSet = new HashSet<>();
                                set3TableFieldValue2Collec(model, field, middleValueList, thirdValueList, valSet);
                            } else { // 非集合对象，直接赋值
                                middleValueList.forEach(valModel -> {
                                    Object middlFrom = ModelUtil.getModelValue(valModel, middlFromFieldName);
                                    if (middlFrom != null && middlFrom.toString().equals(fromFieldValue.toString())) { // model中的值与获取到的对象的主键相同
                                        try {
                                            Object middleToFieldValue = ModelUtil.getModelValue(valModel, link.relationTo()); // model中的值
                                            thirdValueList.forEach(thirdModel -> {
                                                Object thirdTo = ModelUtil.getModelValue(thirdModel, link.to());
                                                if (middleToFieldValue.equals(thirdTo)) { // model中的值与获取到的对象的主键相同
                                                    try {
                                                        field.set(model, thirdModel);
                                                    } catch (IllegalArgumentException | IllegalAccessException e) {
                                                        log.error("设置属性出错", e);
                                                    }
                                                }
                                            });
                                        } catch (Exception e) {
                                            log.error("设置属性出错", e);
                                        }
                                    }
                                });
                            }
                        }

                    }
                });

            });
        }
    }

    /**
     * 查询list里关联对象的值到map中，还没有设置值
     * 
     * @Title thirdTableRelationQueryFieldValues
     * @author 吕凯
     * @date 2021年3月10日 上午10:24:58
     * @param queryModel
     * @param linkFieldValueMap
     * @param middleFieldValMap
     * @param thirdFieldValMap
     * @param linkedQueryModels
     *            void
     */
    private void thirdTableRelationQueryFieldValues(QueryModel queryModel, Map<Field, Set<Object>> linkFieldValueMap,
            Map<Field, List<?>> middleFieldValMap, Map<Field, List<?>> thirdFieldValMap, QueryModel... linkedQueryModels) {
        if (ListUtils.isNotEmpty(linkFieldValueMap.entrySet())) {
            int index = 0;
            for (Map.Entry<Field, Set<Object>> entry : linkFieldValueMap.entrySet()) {
                Field field = entry.getKey();
                Many2Many link = field.getAnnotation(Many2Many.class);
                Class<?> middleModelType = link.relation(); // 获取中间表对象的类型
                String targetPK = link.relationFrom(); // 目标对象的主键
                Description fieldDesc = AnnotationUtil.getFieldDescription(middleModelType, targetPK);
                if (fieldDesc != null) {
                    String targetPKDB = fieldDesc.getDbName(); // 目标对象的主键对应数据库中的名字

                    String queryFields = link.relationFrom() + "," + link.relationTo();
//                        if ("*".equals(queryFields)) { // 查询所有字段，看是否排除某些字段
//                            String queryFieldsExclude = link.queryFieldsExclude(); // 获取不查询的字段 TODO 暂时处理不了
//                        }

//                        QueryModel linkQueryModel = new QueryModel(queryFields); // 关联对象暂不区分对象的state状态
                    // 如果queryFields不为空，并且queryModel未设置选择字段，则将该值写进去
                    /*if (StringUtils.isNotEmpty(queryFields)
                            && ("*".equals(queryModel.getSelectFields()) || "".equals(queryModel.getSelectFields()))) {
                        queryModel.setSelectFields(queryFields);
                    }
                    queryModel.addInSet(targetPKDB, entry.getValue());*/

                    // 中间表使用主表的查询，如果主表查询有条件则也会进入中间表可能出错！！！2022-5-31改为单独的queryModel
                    QueryModel middleQueryModel = new QueryModel(queryFields); // 关联对象暂不区分对象的state状态
                    middleQueryModel.addInSet(targetPKDB, entry.getValue());

                    List<?> middlelinkObj = getBaseDAO().getList(middleModelType, middleQueryModel, 10000); // 查询,限制查询10000条，TODO
                    middleFieldValMap.put(field, middlelinkObj);

                    // 第三个对象
                    Class<?> thirdModelType = ClassUtil.getFieldPojoType(field); // 中间表关联的第三个对象的类型
                    Description fieldDescTo = AnnotationUtil.getFieldDescription(thirdModelType, link.to());
                    if (fieldDescTo != null) {
                        String fieldToDB = fieldDescTo.getDbName(); // 目标对象的主键对应数据库中的名字
//                            QueryModel thireQueryModel = getNormalQueryModel();
//                            QueryModel thireQueryModel = linkedQueryModel;
                        QueryModel thireQueryModel = null;
                        if (linkedQueryModels.length > 0) {
                            if (linkedQueryModels.length >= index + 1) {
                                thireQueryModel = linkedQueryModels[index].copy();
                            } else {
                                thireQueryModel = linkedQueryModels[0].copy(); // 复制关联对象防止多个关联对象直接的干扰
                            }
                        } else {
                            thireQueryModel = new QueryModel(); // 关联对象暂不区分对象的state状态
                        }
//                            QueryModel thireQueryModel = linkedQueryModel.copy(); // 复制关联对象防止多个关联对象直接的干扰
                        Set<Object> thirdModelValueSet = new HashSet<>();
                        middlelinkObj.stream().forEach(middleModel -> {
                            Object relationToValue = ModelUtil.getModelValue(middleModel, link.relationTo());
                            thirdModelValueSet.add(relationToValue);
                        });
                        thireQueryModel.addInSet(fieldToDB, thirdModelValueSet);
                        List<?> thirdObj = getBaseDAO().getList(thirdModelType, thireQueryModel); // 查询第三个表数据
                        thirdFieldValMap.put(field, thirdObj);
                    } else {
                        log.error("关联对象的" + link.to() + "属性不存在(" + thirdModelType + ")");
                    }

                } else {
                    log.error("关联对象的targetField属性不存在" + targetPK + "(" + middleModelType + ")");
                }
                // 所以此处有问题，如果关联数据超过1000条需要自己实现
                index++;
            }
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private <T> void set3TableFieldValue2Collec(T model, Field field, List<?> middleFieldValList, List<?> thirdFieldValList,
            Collection valList) {
        Many2Many link = field.getAnnotation(Many2Many.class);
        String middlFromFieldName = link.relationFrom(); // 目标对象的主键
        String fromFieldName = link.from();
        Object fromFieldValue = ModelUtil.getModelValue(model, fromFieldName); // model中的值
        middleFieldValList.forEach(middleValModel -> {
            Object middlFrom = ModelUtil.getModelValue(middleValModel, middlFromFieldName);
            if (middlFrom != null && middlFrom.toString().equals(fromFieldValue.toString())) { // model中的值与获取到的对象的主键相同
                try {
                    Object middleToFieldValue = ModelUtil.getModelValue(middleValModel, link.relationTo()); // model中的值
                    thirdFieldValList.forEach(thirdModel -> {
                        Object thirdTo = ModelUtil.getModelValue(thirdModel, link.to());
                        if (middleToFieldValue.equals(thirdTo)) { // model中的值与获取到的对象的主键相同
                            valList.add(thirdModel);
                        }
                    });
                } catch (Exception e) {
                    log.error("设置属性出错", e);
                }
            }
        });

        try {
            field.set(model, valList);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            log.error("", e);
        }
    }

    /**
     * 是否查询关联对象
     *
     * @Title queryListLinkObj
     * @author 吕凯
     * @date 2019年7月26日 上午8:21:21
     * @param queryModel
     * @param list
     * @return boolean
     */
    private <T> boolean checkQueryListLinkObj(QueryModel queryModel, List<T> list) {
        return ListUtils.isNotEmpty(list) && list.size() <= 1000 && queryLink && queryModel != null && queryModel.getQueryLink() != null
                && queryModel.getQueryLink();
    }

    /**
     * 将list关联对象的值设置到集合中
     *
     * @Title SetLinkModelFieldValue2Collec
     * @author 吕凯
     * @date 2019年7月25日 下午5:46:06
     * @param model
     * @param field
     * @param targetPK
     * @param linkFieldValue
     * @param fieldValList
     * @param valList
     *            void
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private <T> void setLinkModelFieldValue2Collec(T model, Field field, String targetPK, Object linkFieldValue, List<?> fieldValList,
            Collection valList) {
        fieldValList.forEach(valModel -> {
            Object valModelPK = ModelUtil.getModelValue(valModel, targetPK);
            if (valModelPK != null && valModelPK.toString().equals(linkFieldValue.toString())) { // model中的值与获取到的对象的主键相同
                try {
                    valList.add(valModel);
                } catch (IllegalArgumentException e) {
                    log.error("设置属性出错", e);
                }
            }
        });
        try {
            field.set(model, valList);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            log.error("", e);
        }
    }

    /**
     * 查询单个对象的关联对象
     *
     * @Title queryLinkFields
     * @author 吕凯
     * @date 2019年7月25日 下午5:06:12
     * @param linkQueryModel
     * @param obj
     *            void
     */
    private <T> void queryLinkFields(QueryModel linkQueryModel, T obj) {
        if (checkQueryModelLinkObj(linkQueryModel, obj)) {
            // 2表关联
            secondTableRelationDeal(linkQueryModel, obj);
            // 3表关联
            thirdTableRelationDeal(linkQueryModel, obj);
        }
    }

    /**
     * 单对象的2表关联查询处理
     *
     * @Title secondTableRelationDeal
     * @author 吕凯
     * @date 2019年9月2日 上午9:39:05
     * @param linkQueryModel
     * @param obj
     *            void
     */
    private <T> void secondTableRelationDeal(QueryModel linkQueryModel, T obj) {
//        List<Field> linkFields = AnnotationUtil.getAnnoFields(obj.getClass(), Link.class); // 获取所有的关联字段
        List<Field> linkFields = getLinkFields(obj.getClass(), linkQueryModel);
        if (ListUtils.isNotEmpty(linkFields)) { // 存在关联字段时
            LogUtil.daoDebug("查询级联对象=" + linkFields);
            linkFields.forEach(field -> {
                field.setAccessible(true); // 设为可访问，否则field.set(obj,val)报错
                QueryModel linkQueryModelCopy = getNormalQueryModel();
                if (linkQueryModel != null) {
                    linkQueryModelCopy = linkQueryModel.copy(); // 多个关联查询时，此copy方法会导致源对象的condition和params不一致
                    // BeanUtils.copyProperties(linkQueryModel, linkQueryModelCopy); // 复制关联查询对象，防止多个关联对象时的干扰
                }

                Class<?> fieldType = field.getType();
                Link link = field.getAnnotation(Link.class);
                String targetField = link.targetField();
                String linkFieldName = link.field();
                Object linkFieldValue = ModelUtil.getModelValue(obj, linkFieldName);

                if (linkFieldValue != null) {
                    Class<?> linkFieldType = ClassUtil.getFieldPojoType(field); // 泛型类
                    Description fieldDesc = AnnotationUtil.getFieldDescription(linkFieldType, targetField);
                    if (fieldDesc != null) {
                        String targetPKDB = fieldDesc.getDbName(); // 目标对象的主键对应数据库中的名字
                        linkQueryModelCopy.addEq(targetPKDB, linkFieldValue);
                        // list对象
                        if (fieldType.equals(List.class)) {
                            setLinkModelFieldValue2Collec(obj, field, targetPKDB, linkFieldValue, linkQueryModelCopy);
                        } else if (fieldType.equals(Set.class)) {
                            setLinkModelFieldValue2Collec(obj, field, targetPKDB, linkFieldValue, linkQueryModelCopy);
                        } else { // 非集合对象，直接赋值
                            Object linkObj = getBaseDAO().getOne(fieldType, linkQueryModelCopy);
                            try {
                                field.set(obj, linkObj);
                            } catch (IllegalArgumentException | IllegalAccessException e) {
                                log.error("设置属性出错", e);
                            }
                        }
                    } else {
                        log.error("关联对象的targetField属性不存在" + targetField + "(" + fieldType + ")");
                    }

                }
            });
        }
    }

    /**
     * 将单个对象关联对象的值设置到集合中
     *
     * @Title setLinkModelFieldValue2Collec
     * @author 吕凯
     * @date 2019年7月26日 下午3:28:15
     * @param obj
     * @param field
     * @param targetField
     *            关联数据库中名称
     * @param linkFieldValue
     * @param valList
     *            void
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private <T> void setLinkModelFieldValue2Collec(T obj, Field field, String targetField, Object linkFieldValue,
            QueryModel linkQueryModel) {
//        QueryModel linkQueryModel = getValidQueryModel();
//        linkQueryModel.addEq(targetField, linkFieldValue);
        Class<?> linkFieldType = ClassUtil.getFieldPojoType(field); // 泛型类
        List linkObj = getBaseDAO().getList(linkFieldType, linkQueryModel);
        if (ListUtils.isNotEmpty(linkObj)) {
            try {
                field.set(obj, linkObj);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                log.error("设置属性出错", e);
            }

        }
    }

    /**
     * 单对象的多表关联查询处理
     *
     * @Title thirdTableRelationDeal
     * @author 吕凯
     * @date 2019年9月2日 上午9:39:54
     * @param linkQueryModel
     * @param obj
     *            void
     */
    private <T> void thirdTableRelationDeal(QueryModel linkQueryModel, T obj) {
        // List<Field> linkFields = AnnotationUtil.getAnnoFields(obj.getClass(), Many2Many.class); // 获取所有的关联字段
        List<Field> linkFields = getMany2ManyFields(obj.getClass(), linkQueryModel);
        if (ListUtils.isNotEmpty(linkFields)) { // 存在关联字段时
            LogUtil.daoDebug("查询级联对象=" + linkFields);
            linkFields.forEach(field -> {
                field.setAccessible(true); // 设为可访问，否则field.set(obj,val)报错
                QueryModel linkQueryModelCopy = new QueryModel();
                BeanUtils.copyProperties(linkQueryModel, linkQueryModelCopy); // 复制关联查询对象，防止多个关联对象时的干扰

                Class<?> fieldType = field.getType(); // 当前类中的对象
                Many2Many many2many = field.getAnnotation(Many2Many.class);
                String fromFieldName = many2many.from();
                String relationFromFieldName = many2many.relationFrom();
                Object fromFieldValue = ModelUtil.getModelValue(obj, fromFieldName); // 本对象的查询值
                if (fromFieldValue != null) {
                    Class<?> middleModelType = many2many.relation(); // 当前类中的对象
                    Description fieldDesc = AnnotationUtil.getFieldDescription(middleModelType, relationFromFieldName);
                    if (fieldDesc != null) { // 中间表的from关联字段存在
                        String relationFromDB = fieldDesc.getDbName(); // 目标对象的主键对应数据库中的名字
                        // 查询对应的数据
                        String queryFields = many2many.relationFrom() + "," + many2many.relationTo();
//                      if ("*".equals(queryFields)) { // 查询所有字段，看是否排除某些字段
//                          String queryFieldsExclude = link.queryFieldsExclude(); // 获取不查询的字段 TODO 暂时处理不了
//                      }

//                      QueryModel linkQueryModel = new QueryModel(queryFields); // 关联对象暂不区分对象的state状态
                        // 如果queryFields不为空，并且queryModel未设置选择字段，则将该值写进去
                        /*
                         * QueryModel linkQueryModel = new QueryModel();
                         */
                        if (StringUtils.isNotEmpty(queryFields)
                                && ("*".equals(linkQueryModelCopy.getSelectFields()) || "".equals(linkQueryModelCopy.getSelectFields()))) {
                            linkQueryModelCopy.setSelectFields(queryFields);
                        }
                        linkQueryModelCopy.addEq(relationFromDB, fromFieldValue);
                        List<?> middlelinkObj = getBaseDAO().getList(middleModelType, linkQueryModelCopy); // 查询中间表

                        // 第三个对象
                        Class<?> thirdModelType = ClassUtil.getFieldPojoType(field); // 中间表关联的第三个对象的类型
                        Description fieldDescTo = AnnotationUtil.getFieldDescription(thirdModelType, many2many.to());
                        String fieldToDB = fieldDescTo.getDbName(); // 目标对象的主键对应数据库中的名字
                        List<?> thirdObjList = null;
                        if (fieldToDB != null) {
                            QueryModel thireQueryModel = getNormalQueryModel();
                            Set<Object> thirdModelValueSet = new HashSet<>();
                            middlelinkObj.stream().forEach(middleModel -> {
                                Object relationToValue = ModelUtil.getModelValue(middleModel, many2many.relationTo());
                                thirdModelValueSet.add(relationToValue);
                            });
                            thireQueryModel.addInSet(fieldToDB, thirdModelValueSet);
                            thirdObjList = getBaseDAO().getList(thirdModelType, thireQueryModel); // 查询第三个表数据
                        } else {
                            log.error("关联对象的" + many2many.to() + "属性不存在(" + thirdModelType + ")");
                        }
                        // list对象
                        if (ListUtils.isNotEmpty(thirdObjList)) {
                            if (fieldType.equals(List.class)) {
                                List<?> valList = new ArrayList<>();
                                set3TableFieldValue2Collec(obj, field, thirdObjList, valList);
                            } else if (fieldType.equals(Set.class)) {
                                Set<?> valSet = new HashSet<>();
                                set3TableFieldValue2Collec(obj, field, thirdObjList, valSet);
                            } else { // 非集合对象，直接赋值
                                try {
                                    field.set(obj, thirdObjList.get(0));
                                } catch (IllegalArgumentException | IllegalAccessException e) {
                                    log.error("设置属性出错", e);
                                }
                            }
                        }

                    } else {
                        log.error("关联对象的" + relationFromFieldName + "属性不存在(" + middleModelType + ")");
                    }

                }
            });
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private <T> void set3TableFieldValue2Collec(T obj, Field field, List thirdObj, Collection<?> valList) {
        valList.addAll(thirdObj);
        try {
            field.set(obj, valList);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            log.error("设置属性出错", e);
        }
    }

    /**
     * TODO 用来对比一次查询和多次查询的耗时情况，待删除
     *
     * @Title queryLinkFields2
     * @author 吕凯
     * @date 2019年7月24日 下午5:21:02
     * @param classOfT
     * @param queryModel
     * @param list
     *            void
     */
    private <T> void queryLinkFields2(Class<T> classOfT, QueryModel queryModel, List<T> list) {
        if (checkQueryListLinkObj(queryModel, list)) {
            List<Field> linkFields = getLinkFields(classOfT, queryModel);
            if (ListUtils.isNotEmpty(linkFields)) { // 非空
                // 查出
                list.forEach(model -> {
                    linkFields.forEach(field -> {
                        Class<?> fieldType = field.getType();
                        Link link = field.getAnnotation(Link.class);
                        String linkFieldName = link.field();
                        Object linkFieldValue = ModelUtil.getModelValue(model, linkFieldName);
                        if (linkFieldValue != null) {
                            Object linkObj = getBaseDAO().findById(fieldType, linkFieldValue);
                            try {
                                field.set(model, linkObj);
                            } catch (IllegalArgumentException | IllegalAccessException e) {
                                log.error("设置属性出错", e);
                            }

                        }
                    });
                });
            }
        }
    }

    /**
     * 获取类中关联对象的属性
     *
     * @Title getLinkFields
     * @author 吕凯
     * @date 2019年7月26日 上午9:13:20
     * @param classOfT
     * @param queryModel
     * @return List<Field>
     */
    private <T> List<Field> getLinkFields(Class<T> classOfT, QueryModel queryModel) {
        List<Field> linkFields = new ArrayList<>();
        List<Property<?, ?>> linkFieldFuns = queryModel.getQueryLinkFields();
        // 指定了查询字段，则以指定的优先
        if (ListUtils.isNotEmpty(linkFieldFuns)) {
            linkFieldFuns.forEach(property -> {
                Field field;
                try {
                    field = AnnotationUtil.getField(classOfT, FunctionUtil.getFieldName(property));
                    if (field.isAnnotationPresent(Link.class)) {
                        linkFields.add(field);
                    }
                } catch (Exception e) {
                    log.error("", e);
                }
            });
        } else { // 未指定查询所有带注解的
            List<Field> getLinkFields = AnnotationUtil.getAnnoFields(classOfT, Link.class);
            if (ListUtils.isNotEmpty(getLinkFields)) { // 非空
                linkFields.addAll(getLinkFields); // 获取所有的关联字段
            }
        }
        return linkFields;
    }

    private <T> List<Field> getMany2ManyFields(Class<T> classOfT, QueryModel queryModel) {
        List<Field> linkFields = new ArrayList<>();
        List<Property<?, ?>> linkFieldFuns = queryModel.getQueryLinkFields();
        // 指定了查询字段，则以指定的优先
        if (ListUtils.isNotEmpty(linkFieldFuns)) {
            linkFieldFuns.forEach(property -> {
                Field field;
                try {
                    field = AnnotationUtil.getField(classOfT, FunctionUtil.getFieldName(property));
                    if (field.isAnnotationPresent(Many2Many.class)) {
                        linkFields.add(field);
                    }
                } catch (Exception e) {
                    log.error("", e);
                }
            });
        } else { // 未指定查询所有带注解的
            // 多对多
            List<Field> getMany2ManyFields = AnnotationUtil.getAnnoFields(classOfT, Many2Many.class);
            if (ListUtils.isNotEmpty(getMany2ManyFields)) { // 非空
                linkFields.addAll(getMany2ManyFields); // 获取所有的关联字段
            }
        }
        return linkFields;
    }

    public <T> List<T> getList(Class<T> classOfT, QueryModel queryModel, int size) {
        return getList(classOfT, size, queryModel);
    }

    public <T> List<T> getList(Class<T> classOfT, int size, QueryModel queryModel, QueryModel... linkedQueryModels) {
        List<T> list = getBaseDAO().getList(classOfT, queryModel, size);
        if (linkedQueryModels == null || linkedQueryModels.length == 0) {
            linkedQueryModels = new QueryModel[] { getNormalQueryModel() };
//            linkedQueryModels[0] = getNormalQueryModel();
//            linkedQueryModel = new QueryModel();
//            linkedQueryModel.setQueryLink(queryModel.getQueryLink());
//            linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields());
        }
        queryLinkFields(classOfT, list, queryModel, linkedQueryModels);
        return list;
    }

    public <T> List<T> getObjectList(Class<T> classOfT, String sql, Object... params) {
        return getBaseDAO().getList(classOfT, sql, params);
    }

    public <T> List<T> getList(Class<T> classOfT, String key, Object value) {
        QueryModel queryModel = new QueryModel();
        queryModel.addEq(key, value);
        List<T> list = getList(classOfT, queryModel);
        return list;
    }

    public int getCount(String sql, Object... params) {
        return getBaseDAO().getCount(sql, params);
    }

    public <T> List<T> getList(HttpServletRequest request, Class<T> classOfT, String key, Object value) {
        List<T> obj = getList(classOfT, key, value);
        setRequestAttriList(request, obj);
        return obj;
    }

    public <T> List<T> getList(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        List<T> obj = getList(classOfT, queryModel);
        setRequestAttriList(request, obj);
        return obj;
    }

    public <T> List<T> getList(HttpServletRequest request, Class<T> classOfT, int size, QueryModel queryModel) {
        return getList(request, classOfT, size, queryModel, new QueryModel[0]);
    }

    public <T> List<T> getList(HttpServletRequest request, Class<T> classOfT, int size, QueryModel queryModel,
            QueryModel... linkedQueryModels) {
        List<T> obj = getList(classOfT, size, queryModel, linkedQueryModels);
        setRequestAttriList(request, obj);
        return obj;
    }

    // 带关联对象
    public <T> List<T> getListAndLinks(Class<T> classOfT, QueryModel queryModel, int size) {
        queryModel.setQueryLink(true);
        return getList(classOfT, size, queryModel);
    }

    // 带关联对象
    public <T> List<T> getListAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        queryModel.setQueryLink(true);
        return getList(request, classOfT, queryModel);
    }

    // 带关联对象
    public <T> List<T> getListAndLinks(HttpServletRequest request, Class<T> classOfT, int size, QueryModel queryModel) {
        queryModel.setQueryLink(true);
        return getList(request, classOfT, size, queryModel);
    }

    public <T> List<T> getListAndLinks(HttpServletRequest request, Class<T> classOfT, int size, QueryModel queryModel,
            QueryModel... linkedQueryModels) {
        queryModel.setQueryLink(true);
        return getList(request, classOfT, size, queryModel, linkedQueryModels);
    }

    // join查询
    public <T> List<T> getListByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property) {
        QueryModel queryModel = getSearchQueryModel(request); // 主表查询
        Web.Parameter.dealReqParams(request, queryModel);
        QueryModel linkedQueryModel = new QueryModel(); // 另一个关联表
        Web.Parameter.dealReqParams(request, linkedQueryModel, FunctionUtil.getFieldName(property));
        return getListByJoin(request, classOfT, property, queryModel, linkedQueryModel);
    }

    public <T> List<T> getListByJoin(Class<T> classOfT, Property<T, ?> property) {
        QueryModel queryModel = getValidQueryModel(); // 主表查询
        QueryModel linkedQueryModel = getValidQueryModel(); // 另一个关联表
        return getListByJoin(classOfT, property, queryModel, linkedQueryModel);
    }

    /**
     *
     * 获取List通过join操作
     *
     * @Title getPageBeanByJoin
     * @author 吕凯
     * @date 2019年8月21日 下午3:09:20
     * @param request
     * @param classOfT
     *            主表
     * @param property
     *            主表关联的从表字段
     * @param queryModel
     *            主表查询条件
     * @return List<T>
     */
    public <T> List<T> getListByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property, QueryModel queryModel) {
        QueryModel linkedQueryModel = new QueryModel(); // 另一个关联表
        if (request != null) {
            Web.Parameter.dealReqParams(request, linkedQueryModel, FunctionUtil.getFieldName(property));
        }
        return getListByJoin(request, classOfT, property, queryModel, linkedQueryModel);
    }

    public <T> List<T> getListByJoin(Class<T> classOfT, Property<T, ?> property, QueryModel queryModel) {
        return getListByJoin(request, classOfT, property, queryModel);
    }

    /**
     * 获取List通过join操作
     *
     * @Title getPageBeanByJoin
     * @author 吕凯
     * @date 2019年8月21日 下午2:32:49
     * @param request
     * @param classOfT
     *            主表
     * @param property
     *            主表关联的从表字段
     * @param queryModel
     *            主表查询条件
     * @param linkedQueryModel
     *            从表查询条件
     * @return List<T>
     */
    public <T> List<T> getListByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property, QueryModel queryModel,
            QueryModel linkedQueryModel) {
        List<T> list = new ArrayList<>();
        try {
            list = getBaseDAO().initJoin(classOfT, queryModel).join(property, linkedQueryModel).getListByJoin();
            // linkedQueryModel = getNormalQueryModel(); // 另一个关联表
//            fetchLinks(list, property, queryModel); // 2020-9-2参考getPageBeanByJoin去掉关联查询的条件linkedQueryModel，如果需要可以在子类中覆盖实现
            queryLinkFields(classOfT, list, queryModel); // 2020-9-3修改查询关联对象的方式 吕凯
            if (request != null) {
                setRequestAttriModel(request, list, "list");
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return list;
    }

    public <T> List<T> getListByJoin(Class<T> classOfT, Property<T, ?> property, QueryModel queryModel, QueryModel linkedQueryModel) {
        return getListByJoin(null, classOfT, property, queryModel, linkedQueryModel);
    }

    public <T> List<T> getListBySql(Class<T> classOfT, String sql, Object... params) {
        return getBaseDAO().getListBySql(classOfT, sql, params);
    }

    /**
     * 获取指定字段的值（其他类型通过在queryModel中指定字段类型处理，暂不统一处理）
     *
     * @Title getLongFieldList
     * @author 吕凯
     * @date 2019年5月10日 下午1:40:16
     * @param classOfT
     * @param queryModel
     * @param fields
     * @return List<Long>
     */
    public <T> List<Long> getLongFieldList(Class<T> classOfT, QueryModel queryModel, String fields) {
        queryModel.setSelectFields(fields);
        return getBaseDAO().getLongList(classOfT, queryModel);
    }

    // 执行默认搜索
    public <T> PageNavigationBean<T> doSearch(HttpServletRequest request, Class<T> classOfT) {
        QueryModel queryModel = getSearchQueryModel(request, classOfT);
        PageNavigationBean<T> pageNavigationBean = getPageBean(request, classOfT, queryModel);
        return extendDealPageNavigationBean(pageNavigationBean);
    }

    /**
     *
     * 获取搜索model
     *
     * @Title getSearchQueryModel
     * @author 吕凯
     * @date 2018年7月6日 上午11:53:21
     * @param request
     * @return QueryModel
     */
    public <T> QueryModel getSearchQueryModel(HttpServletRequest request) {
        return getSearchQueryModel(request, null, "");
    }

    public <T> QueryModel getSearchQueryModel(HttpServletRequest request, Class<T> classOfT) {
        return getSearchQueryModel(request, classOfT, "");
    }

    public <T> QueryModel getSearchQueryModel(HttpServletRequest request, String prefix) {
        return getSearchQueryModel(request, null, prefix);
    }

    public <T> QueryModel getSearchQueryModel(HttpServletRequest request, Class<T> classOfT, String prefix) {
        QueryModel queryModel = getValidQueryModel();
        int checkbox = getInt("searchself"); // 只查询自己
        if (checkbox == 1) {
            queryModel.addEq("createBy", Web.Util.getSessionUserId(request));
        }
        return getSearchQueryModel(request, classOfT, queryModel, prefix);
    }

    /**
     * 根据搜索条件前缀返回搜索model，如页面上搜索前缀都为user(user.name,user.loginCode等)
     *
     * @Title getSearchQueryModel
     * @author 吕凯
     * @date 2019年8月21日 下午2:46:24
     * @param request
     * @param queryModel
     * @param prefix
     *            搜索前缀，可以作为分组
     * @return QueryModel
     */
    public <T> QueryModel getSearchQueryModel(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, String prefix) {
        queryModel = Web.Parameter.dealReqParams(request, classOfT, queryModel, prefix);
        queryModel.setOrder("createTime", true); // 默认按时间倒序排列
        extendDealQuery(queryModel);
        return queryModel;
    }

    public <T> QueryModel getSearchQueryModel(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        return getSearchQueryModel(request, classOfT, queryModel, null);
    }

    public QueryModel getSearchQueryModel(HttpServletRequest request, QueryModel queryModel) {
        return getSearchQueryModel(request, null, queryModel, null);
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request) {
        return getNormalSearchQueryModel(request, null, "");
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request, Class<T> classOfT) {
        return getNormalSearchQueryModel(request, classOfT, "");
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request, String prefix) {
        return getNormalSearchQueryModel(request, null, prefix);
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request, Class<T> classOfT, String prefix) {
        QueryModel queryModel = getNormalQueryModel();
        int checkbox = getInt("searchself"); // 只查询自己
        if (checkbox == 1) {
            queryModel.addEq("createBy", Web.Util.getSessionUserId(request));
        }
        return getSearchQueryModel(request, classOfT, queryModel, prefix);
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, String prefix) {
        queryModel = Web.Parameter.dealReqParams(request, classOfT, queryModel, prefix);
        queryModel.addEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_NORMAL);
        queryModel.setOrder("createTime", true); // 默认按时间倒序排列
        extendDealQuery(queryModel);
        return queryModel;
    }

    public <T> QueryModel getNormalSearchQueryModel(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        return getNormalSearchQueryModel(request, classOfT, queryModel, null);
    }

    public QueryModel getNormalSearchQueryModel(HttpServletRequest request, QueryModel queryModel) {
        return getNormalSearchQueryModel(request, null, queryModel, null);
    }

    /**
     * 动态查询 queryModel
     *
     * @author hansai
     * @date 2019-08-08 14:14
     */
    public QueryModel getDynamicConditionSearchQueryModel(HttpServletRequest request, QueryModel queryModel) {
        return Web.Parameter.dealDynamicConditionReqParams(request, queryModel);
    }

    // 用于子类覆盖，扩展doSearch方法中QueryModel的处理（标准queryModel处理完，查询进行前的处理）
    protected QueryModel extendDealQuery(QueryModel queryModel) {
        return queryModel;
    }

    // 用于子类覆盖，扩展doSearch方法中PageNavigationBean的处理（查询完成后进行）
    protected <T> PageNavigationBean<T> extendDealPageNavigationBean(PageNavigationBean<T> pageNavigationBean) {
        return pageNavigationBean;
    }

    // 获取翻页信息
    public <T> PageNavigationBean<T> getPageBean(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        int pageNum = getInt("p");
        return getPageBean(request, classOfT, queryModel, pageNum, PAGE_SIZE);
    }

    public <T> PageNavigationBean<T> getPageBean(Class<T> classOfT, QueryModel queryModel) {
        return getPageBean(null, classOfT, queryModel);
    }

    public <T> PageNavigationBean<T> getPageBean(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, int pageNum,
            int pageSize) {
        QueryModel linkedQueryModel = getNormalQueryModel();
//        linkedQueryModel.setQueryLink(queryModel.getQueryLink());
//        linkedQueryModel.setQueryLinkFields(queryModel.getQueryLinkFields()); // 从主查询条件传递到从查询条件
        return getPageBean(request, classOfT, queryModel, linkedQueryModel, pageNum, pageSize);
    }

    public <T> PageNavigationBean<T> getPageBean(Class<T> classOfT, QueryModel queryModel, int pageNum, int pageSize) {
        return getPageBean(null, classOfT, queryModel, pageNum, pageSize);
    }

    public <T> PageNavigationBean<T> getPageBean(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel,
            QueryModel linkedQueryModel, int pageNum, int pageSize) {
        PageNavigationBean<T> obj = getBaseDAO().getPageNavigationBean(classOfT, queryModel, pageNum, pageSize);
        queryLinkFields(classOfT, obj.getResultList(), queryModel, linkedQueryModel); // 查询关联对象
        setRequestAttriModel(request, obj, "pageBean");
        return obj;
    }

    public <T> PageNavigationBean<T> getPageBean(HttpServletRequest request, Class<T> classOfT, int pageNum, int pageSize,
            QueryModel queryModel, QueryModel... linkedQueryModels) {
        PageNavigationBean<T> obj = getBaseDAO().getPageNavigationBean(classOfT, queryModel, pageNum, pageSize);
        queryLinkFields(classOfT, obj.getResultList(), queryModel, linkedQueryModels); // 查询关联对象
        setRequestAttriModel(request, obj, "pageBean");
        return obj;
    }

    // 获取翻页信息，返回map，用于动态对象的处理，暂不支持关联对象的查询
    public <T> PageNavigationBean<Map<String, Object>> getPageMap(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        int pageNum = getInt("p");
        return getPageMap(request, classOfT, queryModel, pageNum, PAGE_SIZE);
    }

    public <T> PageNavigationBean<Map<String, Object>> getPageMap(Class<T> classOfT, QueryModel queryModel) {
        return getPageMap(null, classOfT, queryModel);
    }

    public <T> PageNavigationBean<Map<String, Object>> getPageMap(Class<T> classOfT, QueryModel queryModel, int pageNum, int pageSize) {
        return getPageMap(null, classOfT, queryModel, pageNum, pageSize);
    }

    public <T> PageNavigationBean<Map<String, Object>> getPageMap(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel,
            int pageNum, int pageSize) {
        PageNavigationBean<Map<String, Object>> obj = getBaseDAO().getPageNavigationMap(classOfT, queryModel, pageNum, pageSize);
        // 查询关联对象 待实现
        setRequestAttriModel(request, obj, "pageBean");
        return obj;
    }

    /**
     * 获取带级联对象的翻页对象
     *
     * @Title getPageBeanAndLinks
     * @author 刘金浩
     * @date 2019年10月25日 上午8:40:56
     * @param request
     * @param classOfT
     * @param queryModel
     * @param linkedQueryModels
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel,
            QueryModel... linkedQueryModels) {
        int pageNum = getInt("p");
        queryModel.setQueryLink(true);
        return getPageBean(request, classOfT, pageNum, PAGE_SIZE, queryModel, linkedQueryModels);
    }

    /**
     * 获取带级联对象的翻页对象
     *
     * @Title getPageBeanAndLinks
     * @author 吕凯
     * @date 2019年8月6日 上午8:40:56
     * @param request
     * @param classOfT
     * @param queryModel
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        int pageNum = getInt("p");
        return getPageBeanAndLinks(request, classOfT, queryModel, pageNum, PAGE_SIZE);
    }

    public <T> PageNavigationBean<T> getPageBeanAndLinks(Class<T> classOfT, QueryModel queryModel) {
        return getPageBeanAndLinks(request, classOfT, queryModel);
    }

    public <T> PageNavigationBean<T> getPageBeanAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel, int pageNum,
            int pageSize) {
        queryModel.setQueryLink(true);
        return getPageBean(request, classOfT, queryModel, pageNum, pageSize);
    }

    /**
     * 此方法为了兼容保留，下个版本删除，建议使用linkedQueryModels参数再最后的方法
     *
     * @Title getPageBeanAndLinks
     * @author 吕凯
     * @date 2020年1月7日 上午10:12:36
     * @param request
     * @param classOfT
     * @param queryModel
     * @param linkedQueryModel
     * @param pageNum
     * @param pageSize
     * @return PageNavigationBean<T>
     */
    @Deprecated
    public <T> PageNavigationBean<T> getPageBeanAndLinks(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel,
            QueryModel linkedQueryModel, int pageNum, int pageSize) {
        linkedQueryModel.setQueryLink(true);
        return getPageBean(request, classOfT, queryModel, linkedQueryModel, pageNum, pageSize);
    }

    public <T> PageNavigationBean<T> getPageBeanAndLinks(HttpServletRequest request, Class<T> classOfT, int pageNum, int pageSize,
            QueryModel queryModel, QueryModel... linkedQueryModels) {
        queryModel.setQueryLink(true);
        return getPageBean(request, classOfT, pageNum, pageSize, queryModel, linkedQueryModels);
    }

    // join操作查询
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property) {
        QueryModel queryModel = getSearchQueryModel(request); // 主表查询
        Web.Parameter.dealReqParams(request, queryModel);

        return getPageBeanByJoin(request, classOfT, property, queryModel);
    }

    /**
     *
     * 获取pageBean通过join操作
     *
     * @Title getPageBeanByJoin
     * @author 吕凯
     * @date 2019年8月21日 下午3:09:20
     * @param request
     * @param classOfT
     *            主表
     * @param property
     *            主表关联的从表字段
     * @param queryModel
     *            主表查询条件
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property,
            QueryModel queryModel) {
        QueryModel linkedQueryModel = new QueryModel(); // 另一个关联表
        return getPageBeanByJoin(request, classOfT, property, queryModel, linkedQueryModel);
    }

    // 同上
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property,
            QueryModel queryModel, QueryModel linkedQueryModel) {
        int pageNum = getInt("p");
        return getPageBeanByJoin(request, classOfT, property, queryModel, linkedQueryModel, pageNum, PAGE_SIZE);
    }

    /**
     * 获取pageBean通过join操作
     *
     * @Title getPageBeanByJoin
     * @author 吕凯
     * @date 2019年8月21日 下午2:32:49
     * @param request
     * @param classOfT
     *            主表
     * @param property
     *            主表关联的从表字段
     * @param queryModel
     *            主表查询条件
     * @param linkedQueryModel
     *            从表查询条件
     * @param pageNum
     *            页码
     * @param pageSize
     *            每页条数
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property,
            QueryModel queryModel, QueryModel linkedQueryModel, int pageNum, int pageSize) {
        return getPageBeanByJoin(request, classOfT, property, queryModel, linkedQueryModel, null, pageNum, pageSize);
    }

    /**
     * 3表关联的join查询，超过3表的不实现按照开发规则也不建议使用join
     * 
     * @Title getPageBeanByJoin
     * @author 刘金浩
     * @date 2020年11月24日 上午8:23:22
     * @param <T>
     * @param request
     * @param classOfT
     * @param property
     *            中model中关联字段
     * @param queryModel
     *            主表查询条件
     * @param linkedQueryModel
     *            中间表查询条件
     * @param otherQueryModel
     *            关联表另一个表的查询条件
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property,
            QueryModel queryModel, QueryModel linkedQueryModel, QueryModel otherQueryModel) {
        int pageNum = getInt("p");
        return getPageBeanByJoin(request, classOfT, property, queryModel, linkedQueryModel, otherQueryModel, pageNum, PAGE_SIZE);
    }

    /**
     * 3表关联的join查询，超过3表的不实现按照开发规则也不建议使用join
     * 
     * @Title getPageBeanByJoin
     * @author 吕凯
     * @date 2020年6月3日 上午8:23:22
     * @param <T>
     * @param request
     * @param classOfT
     * @param property
     *            中model中关联字段
     * @param queryModel
     *            主表查询条件
     * @param linkedQueryModel
     *            中间表查询条件
     * @param otherQueryModel
     *            关联表另一个表的查询条件
     * @param pageNum
     *            页码
     * @param pageSize
     *            每页数量
     * @return PageNavigationBean<T>
     */
    public <T> PageNavigationBean<T> getPageBeanByJoin(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property,
            QueryModel queryModel, QueryModel linkedQueryModel, QueryModel otherQueryModel, int pageNum, int pageSize) {
        PageNavigationBean<T> pageBean = new PageNavigationBean<>();

        String fieldName = FunctionUtil.getFieldName(property);
        Field field = ModelUtil.getField(classOfT, fieldName);
        Class<?> peopertyClazz = ClassUtil.getFieldPojoType(field);
        Web.Parameter.dealReqParams(request, peopertyClazz, linkedQueryModel, fieldName);

        try {
            pageBean = getBaseDAO().initJoin(classOfT, queryModel).join(property, linkedQueryModel, otherQueryModel)
                    .getPageNavigationBeanByJoin(pageNum, pageSize);

            String queryStr = "";
            if (linkedQueryModel != null) {
                queryStr = linkedQueryModel.getNoOrderQueryStrCondition(null);
            }
            if (StringUtils.isEmpty(queryStr)) { // 为空表示没有查询条件
                linkedQueryModel = getValidQueryModel(); // 另一个关联表，关联对象的条件待考虑，
            }
//            fetchLinks(pageBean.getResultList(), property, queryModel); // 2020-6-3去掉关联查询的条件linkedQueryModel，因为已经关联过了貌似没有必要，如果需要可以在子类中覆盖实现
            queryLinkFields(classOfT, pageBean.getResultList(), queryModel); // 2020-9-3修改查询关联对象的方式 吕凯
            setRequestAttriModel(request, pageBean, "pageBean");
        } catch (Exception e) {
            log.error("", e);
        }
        return pageBean;
    }

    public PageNavigationBean<Map<String, Object>> getPageBean(String sql, int pageNum, int pagesize, Object... args) {
        PageNavigationBean<Map<String, Object>> page = new PageNavigationBean<>();
        String tou = "SELECT COUNT(*) AS total FROM (";
        tou = tou + sql + " ) c";
        List<Map<String, Object>> countList = getBaseDAO().getListMapSql(tou, args);

        for (Map<String, Object> map : countList) {
            page.setTotalCount(Integer.parseInt(map.get("total").toString()));
        }
        // 处理pageNum传值小于1时，分页语句报错；
        pageNum = pageNum < 1 ? 1 : pageNum;
        page.setCurrentPage(pageNum);
        pageNum = (pageNum - 1) * pagesize;
        sql = sql + " limit " + pageNum + "," + pagesize;
        List<Map<String, Object>> resultList = getBaseDAO().getListMapSql(sql, args);
        page.setResultList(resultList);
        page.setPageSize(pagesize);
        return page;

    }

    // 获取全部
    public <T> List<T> getAll(Class<T> classOfT) {
        QueryModel queryModel = new QueryModel();
        return getAll(classOfT, queryModel);
    }

    public <T> List<T> getAll(Class<T> classOfT, QueryModel queryModel) {
        return getBaseDAO().getList(classOfT, queryModel);
    }

    public <T> List<T> getAll(HttpServletRequest request, Class<T> classOfT) {
        QueryModel queryModel = new QueryModel();
        List<T> all = getAll(request, classOfT, queryModel);
        setRequestAttriList(request, all);
        return all;
    }

    public <T> List<T> getAll(HttpServletRequest request, Class<T> classOfT, QueryModel queryModel) {
        List<T> all = getBaseDAO().getList(classOfT, queryModel);
        setRequestAttriList(request, all);
        return all;
    }

    // 获取有效的
    public <T> List<T> getAllValid(Class<T> classOfT) {
        QueryModel queryModel = new QueryModel();
        queryModel.addEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_NORMAL);
        return getAll(classOfT, queryModel);
    }

    public <T> List<T> getAllValid(HttpServletRequest request, Class<T> classOfT) {
        QueryModel queryModel = new QueryModel();
        queryModel.addEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_NORMAL);
        return getAll(request, classOfT, queryModel);
    }

    // 2019.03.18 添加 sql + 参数
    public Map<String, Object> getMapSql(String sql, Object... params) {
        return getBaseDAO().getMapSql(sql, params);
    }

    // 2019.03.18 添加 getMapSqlList 方法
    public List<Map<String, Object>> getMapSqlList(String sql, Object... params) {
        return getBaseDAO().getListMapSql(sql, params);
    }

    /**
     * 返回mapList
     * 
     * @Title getMapSqlList
     * @author 吕凯
     * @date 2020年11月30日 下午6:19:34
     * @param <T>
     * @param classOfT
     * @param queryModel
     * @return List<Map<String,Object>>
     */
    public <T> List<Map<String, Object>> getMapList(Class<T> classOfT, QueryModel queryModel) {
        return getBaseDAO().getMapList(classOfT, queryModel);
    }

    /**
     * 返回map
     * 
     * @Title getMap
     * @author 吕凯
     * @date 2020年11月30日 下午6:19:48
     * @param <T>
     * @param classOfT
     * @param queryModel
     * @return Map<String,Object>
     */
    public <T> Map<String, Object> getMap(Class<T> classOfT, QueryModel queryModel) {
        return getBaseDAO().getMap(classOfT, queryModel);
    }

    // 添加/更新
    /*
     * public <T> Result addOrUpdate(Class<T> modelType, boolean update) { return addOrUpdate(WebUtil.getModel(request, modelType), update,
     * "id", Web.Util.getSessionUserId(request)); }
     */
    public <T> Result addOrUpdate(T modelBean, boolean update) {
        return addOrUpdate(modelBean, update, "id", Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result addOrUpdate(T modelBean, boolean update, Long userId, String userName) {
        return addOrUpdate(modelBean, update, "id", userId, userName);
    }

    public <T> Result addOrUpdate(T modelBean, boolean update, String key, Long userId, String userName) {
        return addOrUpdate(modelBean, update, null, key, userId, userName);
    }

    public <T> Result addOrUpdate(T modelBean, boolean update, String updateFieldsEvenNull) {
        return addOrUpdate(modelBean, update, updateFieldsEvenNull, "id", Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    /**
     * 更新指定字段，即使指定字段为null也更新，与updateSpecifiedFields的区别是updateSpecifiedFields只更新指定字段，而该方法如果其他字段不为null也会更新
     * 
     * @Title updateFieldsEvenNull
     * @author 吕凯
     * @date 2021年7月26日 上午11:13:27
     * @param <T>
     * @param modelBean
     * @param update
     * @param updateFieldsEvenNull
     * @param userId
     * @param userName
     * @return Result
     */
    public <T> Result updateFieldsEvenNull(T modelBean, boolean update, String updateFieldsEvenNull, Long userId, String userName) {
        return addOrUpdate(modelBean, update, updateFieldsEvenNull, "id", userId, userName);
    }

    /**
     * 
     * 更新指定字段，即使指定字段为null也更新，与updateSpecifiedFields的区别是updateSpecifiedFields只更新指定字段，而该方法如果其他字段不为null也会更新
     * 
     * @Title updateFieldsEvenNull
     * @author 吕凯
     * @date 2021年8月24日 下午4:27:53
     * @param <T>
     * @param modelBean
     * @param updateFieldsEvenNull
     *            更新字段，多个字段用逗号连接
     * @param userId
     * @param userName
     * @return Result
     */
    public <T> Result updateFieldsEvenNull(T modelBean, String updateFieldsEvenNull, Long userId, String userName) {
        return updateFieldsEvenNull(modelBean, true, updateFieldsEvenNull, userId, userName);
    }

    /**
     * 
     * 更新指定字段，即使指定字段为null也更新，与updateSpecifiedFields的区别是updateSpecifiedFields只更新指定字段，而该方法如果其他字段不为null也会更新
     * 
     * @Title updateFieldsEvenNull
     * @author 吕凯
     * @date 2021年8月24日 下午4:26:25
     * @param <T>
     * @param modelBean
     * @param updateFieldsEvenNull
     *            更新字段，多个字段用逗号连接
     * @return Result
     */
    public <T> Result updateFieldsEvenNull(T modelBean, String updateFieldsEvenNull) {
        return updateFieldsEvenNull(modelBean, true, updateFieldsEvenNull, Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    public <T> Result addOrUpdate(T modelBean, boolean update, Property<T, ?> property) {
        return addOrUpdate(modelBean, update, FunctionUtil.getFieldName(property), "id", Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    // 强制更新多个字段，即为null仍然更新
    public <T> Result addOrUpdate(T modelBean, boolean update, List<Property<T, ?>> propertys) {
        List<String> updateFieldsEvenNullList = new ArrayList<>();
        if (ListUtils.isNotEmpty(propertys)) {
            propertys.forEach(property -> {
                updateFieldsEvenNullList.add(FunctionUtil.getFieldName(property));
            });
        }
        String updateFieldsEvenNull = null;
        if (ListUtils.isNotEmpty(updateFieldsEvenNullList)) {
            updateFieldsEvenNull = String.join(",", updateFieldsEvenNullList);
        }
        return addOrUpdate(modelBean, update, updateFieldsEvenNull, "id", Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    /**
     * 更新指定的字段，其他字段不更新
     * 
     * @Title updateSpecifiedFields
     * @author 吕凯
     * @date 2021年7月26日 上午9:45:53
     * @param <T>
     * @param modelBean
     * @param updateFieldsEvenNull
     *            为更新的字段，用逗号（英文）分隔
     * @return Result
     */
    public <T> Result updateSpecifiedFields(T modelBean, String updateFieldsEvenNull) {
        return updateSpecifiedFields(modelBean, updateFieldsEvenNull, "id", Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    public <T> Result updateSpecifiedFields(T modelBean, String updateFieldsEvenNull, Long userId, String userName) {
        return updateSpecifiedFields(modelBean, updateFieldsEvenNull, "id", userId, userName);
    }

    /**
     * 只更新指定字段，其他字段一概不更新
     * 
     * @Title updateSpecifiedFields
     * @author 吕凯
     * @date 2021年7月26日 上午10:09:37
     * @param <T>
     * @param modelBean
     * @param updateFieldsEvenNull
     * @param key
     * @param userId
     * @param userName
     * @return Result
     */
    public <T> Result updateSpecifiedFields(T modelBean, String updateFieldsEvenNull, String key, Long userId, String userName) {
        long time0 = System.currentTimeMillis();
        try {
            // 赋值新的防止后续有其他操作
            Object beanCopy = org.apache.commons.beanutils.BeanUtils.cloneBean(modelBean);
            // 获取字段list
            List<String> fieldList = new ArrayList<>(Arrays.asList(updateFieldsEvenNull.toLowerCase().split(",")));
            fieldList.add(key);
            // 获取field列表
            Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(beanCopy.getClass());
            for (Entry<String, Field> e : fieldMap.entrySet()) {
                Field field = e.getValue();
                // 判断是否为private属性
                OnlyShow onlyShowTag = field.getAnnotation(OnlyShow.class);
                boolean onlyShow = false; // 纯展示
                if (onlyShowTag != null && onlyShowTag.value()) {
                    onlyShow = true;
                }
                if (field.getModifiers() == 2 && !onlyShow) {
                    field.setAccessible(true);
                    try {
                        // 如果不在指定字段内则设置为空
                        if (!fieldList.contains(field.getName().toLowerCase())) {
                            field.set(beanCopy, null);
                        }
                    } catch (Exception e1) {
                        log.error("设置为null失败！", e1);
                    }
                }

            }
            long time1 = System.currentTimeMillis();
            // log.warn("speed time ===" + (time1 - time0));
            return addOrUpdate(beanCopy, true, updateFieldsEvenNull, key, userId, userName);
        } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e2) {
            log.error("", e2);
        }
        return ResultUtil.error("更新失败！");
    }

    /**
     *
     * 添加或者更新
     *
     * @Title addOrUpdate
     * @author 吕凯
     * @date 2019年10月14日 下午2:36:55
     * @param modelBean
     * @param update
     *            是否为更新
     * @param updateFieldsEvenNull
     *            更新的字段（更新时用，有此字段时updateAllField不生效）
     * @param key
     *            model的主键
     * @param userId
     *            操作的用户id
     * @return Result
     */
    private <T> Result addOrUpdate(T modelBean, boolean update, String updateFieldsEvenNull, String key, Long userId, String userName) {
        Result result = new Result();
        // 需要需要判断数据权限
        String modelShowName = AnnotationUtil.getModelShowName(modelBean); // model展示名称
        String operateName = "添加";
        Boolean flag = false;
        Object pkValue = ModelUtil.getModelValue(modelBean, key);
        setUpdateInfo(modelBean, userId, userName);

        // 查询唯一性约束是否有违反
        Result checkResult = checkUnique(modelBean, update, key, modelShowName, operateName, pkValue);
        if (!checkResult.getSuccess()) {
            return checkResult;
        }
        try {
            if (update) {
                operateName = "修改";
                if (StringUtils.isNoneBlank(updateFieldsEvenNull)) {
                    flag = getBaseDAO().updateEvenNull(modelBean, updateFieldsEvenNull, key);
                } else {
                    flag = getBaseDAO().update(modelBean, key);
                }
            } else {
                if (ModelUtil.hasField(modelBean, key)) {
                    if (ModelUtil.getModelValue(modelBean, key) == null) { // 主键值未设定则自动赋值
                        pkValue = PKUtil.nextId();
                        ModelUtil.setModelValue(modelBean, key, pkValue);
                    }
                }
                setCreateInfo(modelBean, userId, userName);
                flag = getBaseDAO().save(modelBean);
            }
            flag = extendAddOrUpdate(flag, modelBean, update, key, userId);
        } catch (Exception e) {
            flag = false;
            result.setMessage(e.getMessage());
            log.error("", e);
        }
        if (flag) {
//            return Web.Response.success(operateName + modelShowName + "信息成功！（" + key + "：" + pkValue + "）", modelBean);
            return Web.Response.success(operateName + modelShowName + "信息成功！", modelBean);
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！" + result.getMessage());
        }
    }

    // 关联对象保存修改，待实现
    /*
     * public <T> Result saveWith(T modelBean, Property<T, ?> property) { return addOrUpdate(modelList, update, "id",
     * Web.Util.getSessionUserId(request)); }
     */

    // 批量添加/更新
    public <T> Result addOrUpdate(List<T> modelList, boolean update) {
        return addOrUpdate(modelList, update, "id", Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result addOrUpdate(List<T> modelList, boolean update, Long userId, String userName) {
        return addOrUpdate(modelList, update, "id", userId, userName);
    }

    public <T> Result addOrUpdate(List<T> modelList, boolean update, String key, Long userId, String userName) {
        Result result = new Result();
        Boolean flag = false;
        if (ListUtils.isNotEmpty(modelList)) {
            try {
                String operateName = "添加";
                if (update) {
                    operateName = "修改";
                }
                String modelShowName = "";
                for (T modelBean : modelList) {
                    // 需要需要判断数据权限
                    modelShowName = AnnotationUtil.getModelShowName(modelBean); // model展示名称
                    Object pkValue = ModelUtil.getModelValue(modelBean, key);
                    setUpdateInfo(modelBean, userId, userName);

                    // 查询唯一性约束是否有违反
                    Result checkResult = checkUnique(modelBean, update, key, modelShowName, operateName, pkValue);
                    if (!checkResult.getSuccess()) {
                        return checkResult;
                    }
                    if (update) {
                        flag = getBaseDAO().update(modelBean, key);
                    } else {
                        if (ModelUtil.hasField(modelBean, key)) {
                            if (ModelUtil.getModelValue(modelBean, key) == null) { // 主键值未设定则自动赋值
                                pkValue = PKUtil.nextId();
                                ModelUtil.setModelValue(modelBean, key, pkValue);
                            }
                        }
                        setCreateInfo(modelBean, userId, userName);
                        flag = getBaseDAO().save(modelBean);
                    }
                }
                flag = extendAddOrUpdate(flag, modelList, update, key, userId);
                if (!flag) {
                    result.setMessage(operateName + modelShowName + "信息失败！" + result.getMessage());
                }
                result.setSuccess(flag);
            } catch (Exception e) {
                flag = false;
                result.setMessage(e.getMessage());
                log.error("", e);
            }
        }
        return result;

    }

    /**
     * 查询唯一性约束是否有违反
     *
     * @Title checkUnique
     * @author 吕凯
     * @date 2019年1月16日 下午4:34:14
     * @param modelBean
     * @param update
     * @param key
     * @param modelShowName
     * @param operateName
     * @param pkValue
     * @return Result
     */
    protected <T> Result checkUnique(T modelBean, boolean update, String key, String modelShowName, String operateName, Object pkValue) {
        if (modelBean != null) {
            List<List<Description>> fieldNames = AnnotationUtil.getUniqueFieldName(modelBean.getClass());
            if (ListUtils.isNotEmpty(fieldNames)) {
                for (List<Description> fields : fieldNames) {
//                    String fieldShowName = "";
                    StringBuilder fieldShowName = new StringBuilder("");
                    QueryModel queryModel = new QueryModel();
                    if (update) {
                        queryModel.addUnEq(key, pkValue); // 排除自己，未处理表名称与字段名称不一致的情况
                    }
                    if (AnnotationUtil.hasField(modelBean, StaticParams.DB_FILED_STATE)) { // 排除掉删除的数据
                        queryModel.addUnEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_DELETE);
                    }
                    if (fields.size() == 1) {
                        Description fieldDescp = fields.get(0);
                        String fieldName = fieldDescp.getName();
                        String dbColName = fieldDescp.getName();
//                        fieldShowName += fieldDescp.getShowName();
                        fieldShowName.append(fieldDescp.getShowName());
                        Object fieldValue = ModelUtil.getModelValue(modelBean, fieldName);
                        queryModel.addEq(dbColName, fieldValue);
                        if (fieldValue == null) { // 值为空则不处理
                            return Web.Response.success("");
                        }
                    } else { // 大于1个，联合字段
                        Map<String, Object> valueMap = new HashMap<>();
                        boolean isAllValEmpty = true;
                        for (Description fieldDescp : fields) {
                            String fieldName = fieldDescp.getName();
                            String dbColName = fieldDescp.getDbName();
//                            fieldShowName += " " + fieldDescp.getShowName() + " ";
                            fieldShowName.append(" ").append(fieldDescp.getShowName()).append(" ");
                            Object fieldValue = ModelUtil.getModelValue(modelBean, fieldName);
                            valueMap.put(dbColName, fieldValue);
                            if (fieldValue != null) {
                                isAllValEmpty = false;
                            }
                        }
                        if (isAllValEmpty) { // 所有值都为空，则不查询
                            return Web.Response.success("");
                        }
                        for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
                            queryModel.addEq(entry.getKey(), entry.getValue());
                        }
                    }
                    boolean exist = getBaseDAO().exists(modelBean.getClass(), queryModel);
                    if (exist) {
                        return Web.Response.error(operateName + modelShowName + "信息失败！“" + fieldShowName + "”存在重复数据！");
                    }
                }
            }
        }
        return Web.Response.success("");
    }

    // addOrUpdate子类扩展（addOrUpdate完成后进行）
    protected <T> boolean extendAddOrUpdate(Boolean flag, T modelBean, boolean update, String key, Long userId) {
        return flag;
    }

    // addOrUpdate子类扩展批量操作（addOrUpdate完成后进行）
    protected <T> boolean extendAddOrUpdate(Boolean flag, List<T> modelBean, boolean update, String key, Long userId) {
        return flag;
    }

    /**
     * 设置创建人创建时间等信息
     *
     * @Title setCreateInfo
     * @author 吕凯
     * @date 2019年1月14日 下午3:26:29
     * @param modelBean
     * @param userId
     *            void
     */
    public <T> void setCreateInfo(T modelBean, Long userId, String userName) {
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_BY)) { // 存在并且不是只展示字段
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_CREATE_BY) == null) {
                if (userId != null && userId != 0L) {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_BY, userId);
                } else {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_BY, 0L);
                }
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_NAME)) { // 创建人姓名
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_CREATE_NAME) == null) {
                if (userId != null && userId != 0L) {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_NAME,
                            userName == null ? getBaseDAO().findById(userCls, userId).getUserName() : userName);
                }
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_TIME)) {
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_CREATE_TIME) == null) {
                ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_TIME, new Date());
            }
        }
    }

    /**
     * 填充修改人、修改时间等信息
     *
     * @Title setUpdateInfo
     * @author 吕凯
     * @date 2019年1月14日 下午3:25:57
     * @param modelBean
     * @param userId
     *            void
     */
    public <T> void setUpdateInfo(T modelBean, Long userId, String userName) {
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_BY)) { // 存在并且不是只展示字段
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_UPDATE_BY) == null) {
                if (userId != null && userId != 0L) {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_BY, userId);
                } else {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_BY, 0L);
                }
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_NAME)) { // 修改人姓名
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_UPDATE_NAME) == null) {
                if (userId != null && userId != 0L) {
                    ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_NAME,
                            userName == null ? getBaseDAO().findById(userCls, userId).getUserName() : userName);
                }
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_TIME)) {
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_UPDATE_TIME) == null) {
                ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_TIME, new Date());
            }
        }
    }

    /**
     * 将修改信息设空
     * 
     * @Title setUpdateInfoEmpty
     * @author 吕凯
     * @date 2021年6月11日 上午8:50:02
     * @param <T>
     * @param modelBean
     *            void
     */
    public <T> void setUpdateInfoEmpty(T modelBean) {
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_BY)) { // 存在并且不是只展示字段
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_BY, null);
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_NAME)) { // 修改人姓名
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_NAME, null);
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_UPDATE_TIME)) {
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_UPDATE_TIME, null);
        }
    }

    /**
     * 将创建人信息置空
     * 
     * @Title setCreateInfoEmpty
     * @author 吕凯
     * @date 2021年12月30日 上午9:58:39
     * @param <T>
     * @param modelBean
     *            void
     */
    public <T> void setCreateInfoEmpty(T modelBean) {
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_BY)) { // 存在并且不是只展示字段
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_BY, null);
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_NAME)) { // 创建人姓名
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_NAME, null);
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_CREATE_TIME)) {
            ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_CREATE_TIME, null);
        }
    }

    // 审核
    public <T> Result audit(T modelBean) {
        // 需要需要判断数据权限
        return audit(modelBean, "id", Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result audit(T modelBean, Long userId, String userName) {
        // 需要需要判断数据权限
        return audit(modelBean, "id", userId, userName);
    }

    public <T> Result audit(T modelBean, String key, Long userId, String userName) {
        // 需要需要判断数据权限
        String operateName = "审核";
        boolean flag = false;
        String modelShowName = AnnotationUtil.getModelShowName(modelBean); // model展示名称
//        Object pkValue = ModelUtil.getModelValue(modelBean, key);
        setAuditInfo(modelBean, userId, userName);
        flag = getBaseDAO().update(modelBean, key);
        if (flag) {
            return Web.Response.success(operateName + modelShowName + "信息成功！", modelBean);
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！");
        }
    }

    /**
     * 填充审核人、审核时间等信息
     * 
     * @Title setAuditInfo
     * @author 吕凯
     * @date 2020年9月15日 上午11:56:12
     * @param <T>
     * @param modelBean
     * @param userId
     * @param userName
     *            void
     */
    public <T> void setAuditInfo(T modelBean, Long userId, String userName) {// 存在并且不是只展示字段
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_APPROVED_BY)) { // 审核人
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_APPROVED_BY) == null) {
                ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_APPROVED_BY, userId);
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_APPROVED_NAME)) { // 审核姓名
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_APPROVED_NAME) == null) {
                ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_APPROVED_NAME,
                        userName == null ? getBaseDAO().findById(userCls, userId).getUserName() : userName);
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(modelBean, StaticParams.DB_FILED_APPROVED_TIME)) { //// 审核时间
            if (ModelUtil.getModelValue(modelBean, StaticParams.DB_FILED_APPROVED_TIME) == null) {
                ModelUtil.setModelValue(modelBean, StaticParams.DB_FILED_APPROVED_TIME, new Date());
            }
        }
    }

    /**
     * 物理删除数据，慎用！！！！！，建议使用remove方法，逻辑删除
     *
     * @Title del
     * @author 吕凯
     * @date 2018年6月27日 下午3:49:36
     * @param classOfT
     * @param id
     * @return Result
     */
    public <T> Result del(Class<T> classOfT, Long id) {
        return del(classOfT, "id", id);
    }

    /**
     * 
     * 物理删除数据，慎用！！！！！，建议使用remove方法，逻辑删除（扩展方法）
     * 
     * @Title del
     * @author 武杨
     * @date 2021年5月8日 下午2:56:38
     * @param <T>
     * @param classOfT
     * @param property
     * @param keyValue
     * @return Result
     */
    public <T> Result del(Class<T> classOfT, Property<T, ?> property, Object keyValue) {
        return del(classOfT, FunctionUtil.getFieldName(property), keyValue);
    }

    /**
     *
     * 物理删除数据，慎用！！！！！，建议使用remove方法，逻辑删除
     *
     * @Title del
     * @author 吕凯
     * @date 2018年6月27日 下午3:50:06
     * @param classOfT
     * @param key
     * @param keyValue
     * @return Result
     */
    public <T> Result del(Class<T> classOfT, String key, Object keyValue) {
        // 需要需要判断数据权限
        String operateName = "删除";
        String modelShowName = AnnotationUtil.getModelShowName(classOfT); // model展示名称
        boolean flag = getBaseDAO().delete(classOfT, key, keyValue);
        if (flag) {
            return Web.Response.success(operateName + modelShowName + "信息成功！", key + ":" + keyValue);
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！");
        }
    }

    /**
     *
     * 批量物理删除数据，慎用！！！！！，建议使用remove方法，逻辑删除
     *
     * @Title del
     * @author 吕凯
     * @date 2018年6月27日 下午3:50:06
     * @param classOfT
     * @param key
     * @param keyValues
     * @return Result
     */
    public <T> Result batchDel(Class<T> classOfT, String key, Object... keyValues) {
        // 需要需要判断数据权限
        String operateName = "批量删除";
        String modelShowName = AnnotationUtil.getModelShowName(classOfT); // model展示名称
        boolean flag = getBaseDAO().batchDelete(classOfT, key, keyValues);
        if (flag) {
            log.warn(operateName + modelShowName + "信息成功！（key:" + key + "=" + StringUtils.join(keyValues, ",") + "）");
            return Web.Response.success(operateName + modelShowName + "信息成功！（" + keyValues.length + "条）");
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！");
        }
    }

    public <T> Result batchDel(Class<T> classOfT, Object... idValues) {
        return batchDel(classOfT, "id", idValues);
    }

    /**
     * 逻辑级联删除
     *
     * @Title removeAndLinks
     * @author 刘金浩
     * @date 2018年6月27日 下午4:00:57
     * @param classOfT
     * @param id
     * @return Result
     */
    // @Transaction(value = "removeAndLinks")
    public <T> Result removeAndLinks(Class<T> classOfT, Long id) {
        QueryModel linkedQueryModel = new QueryModel();
        linkedQueryModel.setQueryLink(true);
        return removeAndLinks(classOfT, id, linkedQueryModel);
    }

    /**
     *
     * 逻辑级联删除
     *
     * @Title removeAndLinks
     * @author 吕凯
     * @date 2019年11月1日 下午4:17:12
     * @param classOfT
     * @param linkedQueryModel
     *            可以在里面指定级联删除的关联字段
     * @param id
     * @return Result
     */
    public <T> Result removeAndLinks(Class<T> classOfT, Long id, QueryModel linkedQueryModel) {
        TransactionManager.start();
        Result result = new Result();
        try {
            T obj = getOne(classOfT, id);
            result = remove(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request)); // 删除主表，逻辑删除
            if (result.getSuccess()) { // 成功
                linkedQueryModel.setQueryLink(true);
                removeLinkFields(linkedQueryModel, obj); // 级联删除
            }
            TransactionManager.commit();
        } catch (Exception e) {
            log.error("级联删除数据失败", e);
            try {
                TransactionManager.rollback(); // 回滚
            } catch (SQLException e1) {
            }
            return Web.Response.error("级联删除数据失败！" + e.getMessage());
        }
        return result;
    }

    /**
     *
     * 根据条件进行级联删除
     *
     * @Title removeLinkFields
     * @author 刘金浩
     * @date 2019年10月31日 下午4:10:33
     * @param queryModel
     * @param obj
     *            void
     */
    private <T> void removeLinkFields(QueryModel queryModel, T obj) {
        if (checkQueryModelLinkObj(queryModel, obj)) {
            // 2表关联
            removeTableRelationDeal(queryModel, obj);
        }
    }

    /**
     *
     * 级联逻辑删除关联表数据
     *
     * @Title removeTableRelationDeal
     * @author 刘金浩
     * @date 2019年10月31日 下午4:10:41
     * @param queryModel
     * @param obj
     *            void
     */
    private <T> void removeTableRelationDeal(QueryModel queryModel, T obj) {
        List<Field> linkFields = getLinkFields(obj.getClass(), queryModel); // 可以指定关联字段
//        List<Field> linkFields = AnnotationUtil.getAnnoFields(obj.getClass(), Link.class); // 获取所有2表关联的关联字段
        if (ListUtils.isNotEmpty(linkFields)) { // 存在关联字段时
            LogUtil.daoDebug("待删除的级联字段=" + linkFields);
            linkFields.forEach(field -> {
                Link link = field.getAnnotation(Link.class);
                String targetField = link.targetField();
                String linkFieldName = link.field();
                Object linkFieldValue = ModelUtil.getModelValue(obj, linkFieldName);
                if (linkFieldValue != null) {
                    Class<?> linkFieldType = ClassUtil.getFieldPojoType(field); // 泛型类
                    remove(linkFieldType, targetField, linkFieldValue);
                }
            });
        }
    }

    /**
     * 逻辑删除
     *
     * @Title remove
     * @author 吕凯
     * @date 2018年6月27日 下午4:00:57
     * @param classOfT
     * @param id
     * @return Result
     */
    public <T> Result remove(Class<T> classOfT, Long id) {
        return remove(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result remove(Class<T> classOfT, Property<T, ?> property, Object keyValue) {
        return remove(classOfT, FunctionUtil.getFieldName(property), keyValue, null, Web.Util.getSessionUserId(request),
                Web.Util.getSessionUserName(request));
    }

    public <T> Result remove(Class<T> classOfT, String key, Object keyValue) {
        return remove(classOfT, key, keyValue, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result remove(Class<T> classOfT, Long id, Long userId, String userName) {
        return remove(classOfT, "id", id, null, userId, userName);
    }

    public <T> Result remove(Class<T> classOfT, Long id, String parKey, Long userId, String userName) {
        return remove(classOfT, "id", id, parKey, userId, userName);
    }

    public <T> Result remove(Class<T> classOfT, String key, Object keyValue, String parKey, Long userId, String userName) {
        return remove(classOfT, key, keyValue, StaticParams.STATE_DELETE, parKey, userId, userName);
    }

    public <T> Result remove(Class<T> classOfT, String key, Object keyValue, Integer status, String parKey, Long userId, String userName) {
        // 需要需要判断数据权限
        Result result = new Result();
        T t;
        Boolean flag = false;
        String operateName = "删除";
        if (StaticParams.STATE_DISABLE.equals(status)) {
            operateName = "停用";
        } else if (StaticParams.STATE_FREEZE.equals(status)) {
            operateName = "冻结";
        } else if (StaticParams.STATE_UNFREEZE.equals(status)) {
            operateName = "解除冻结";
            status = StaticParams.STATE_NORMAL;
        } else if (StaticParams.STATE_ENABLE.equals(status)) {
            operateName = "启用";
            status = StaticParams.STATE_NORMAL;
        }
        String modelShowName = "";
        try {
            t = classOfT.newInstance();
            modelShowName = AnnotationUtil.getModelShowName(t); // model展示名称
            ModelUtil.setModelValue(t, key, keyValue);
            ModelUtil.setModelValue(t, StaticParams.DB_FILED_STATE, status);
            setUpdateInfo(t, userId, userName);
            Description fieldDesc = AnnotationUtil.getFieldDescription(classOfT, key);
            if (fieldDesc != null) {
                key = fieldDesc.getDbName(); // 目标对象的主键对应数据库中的名字
            }
            flag = getBaseDAO().update(t, key);
            if (StringUtils.isNotBlank(parKey)) { // 删除相关子类
                if (ModelUtil.hasField(t, parKey)) {
                    operateName += "(级联子类)";
                    t = classOfT.newInstance();
                    ModelUtil.setModelValue(t, parKey, keyValue);
                    ModelUtil.setModelValue(t, StaticParams.DB_FILED_STATE, status);
                    Description fieldParKeyDesc = AnnotationUtil.getFieldDescription(t, parKey);
                    if (fieldParKeyDesc != null) {
                        parKey = fieldParKeyDesc.getDbName(); // 目标对象的主键对应数据库中的名字
                    }
                    flag = getBaseDAO().update(t, parKey);
                }
            }
            flag = extendRemove(flag, classOfT, key, keyValue, status, userId);
        } catch (Exception e) {
            flag = false;
            result.setMessage(e.getMessage());
            log.error("", e);
        }
        if (flag) {
            return Web.Response.success(operateName + modelShowName + "信息成功！", key + ":" + keyValue);
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！" + result.getMessage());
        }
    }

    // 评论删除（逻辑删除）
    public <T> Result batchRemove(Class<T> classOfT, Object... keyValues) {
        return batchRemove(classOfT, StaticParams.DB_FILED_STATE, StaticParams.STATE_DELETE, keyValues);
    }

    public <T> Result batchRemove(Class<T> classOfT, Integer status, Object... keyValues) {
        return batchRemove(classOfT, StaticParams.DB_FILED_STATE, status, keyValues);
    }

    public <T> Result batchRemove(Class<T> classOfT, String colName, Integer status, Object... keyValues) {
        // 需要需要判断数据权限
        String operateName = "删除";
        if (StaticParams.STATE_DISABLE.equals(status)) {
            operateName = "停用";
        } else if (StaticParams.STATE_FREEZE.equals(status)) {
            operateName = "冻结";
        } else if (StaticParams.STATE_UNFREEZE.equals(status)) {
            operateName = "解除冻结";
            status = StaticParams.STATE_NORMAL;
        } else if (StaticParams.STATE_ENABLE.equals(status)) {
            operateName = "启用";
            status = StaticParams.STATE_NORMAL;
        }
        String tableName = getBaseDAO().getTableName(classOfT);
        String modelShowName = AnnotationUtil.getModelShowName(classOfT); // model展示名称
        String sql = "update " + tableName + " set " + colName + " = ? where id = ?";
        Object[][] params = new Object[keyValues.length][2];
        int i = 0;
        for (Object id : keyValues) { // 组合参数，批量删除的参数为二维数组，同一下标的一组数组为一条sql的参数
            params[i][0] = status;
            params[i][1] = id;
            i++;
        }
        boolean flag = getBaseDAO().batchUpdate(sql, params) > 0;
        if (flag) {
            return Web.Response.success(operateName + modelShowName + "信息成功！（" + keyValues.length + "条）");
        } else {
            return Web.Response.error(operateName + modelShowName + "信息失败！");
        }
    }

    /**
     * 级联子类删除，默认主键id，父类id 为pid
     *
     * @Title removeCasePar
     * @author 吕凯
     * @date 2018年7月6日 上午10:39:23
     * @param classOfT
     * @param id
     * @return Result
     */
    public <T> Result removeCaseChild(Class<T> classOfT, Long id, Long userId, String userName) {
        return remove(classOfT, "id", id, "pid", userId, userName);
    }

    // 删除方法子类扩展（删除完成后进行）
    protected <T> boolean extendRemove(Boolean flag, Class<T> classOfT, String key, Object value, Integer status, Long userId) {
        return true;
    }

    // 冻结
    public <T> Result freeze(Class<T> classOfT, Long id) {
        return freeze(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result freeze(Class<T> classOfT, String key, Object keyValue) {
        return freeze(classOfT, key, keyValue, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result freeze(Class<T> classOfT, Long id, Long userId, String userName) {
        return freeze(classOfT, "id", id, null, userId, userName);
    }

    public <T> Result freeze(Class<T> classOfT, Long id, String parKey, Long userId, String userName) {
        return freeze(classOfT, "id", id, parKey, userId, userName);
    }

    public <T> Result freeze(Class<T> classOfT, String key, Object keyValue, String parKey, Long userId, String userName) {
        return remove(classOfT, key, keyValue, StaticParams.STATE_FREEZE, parKey, userId, userName);
    }

    // 解除冻结
    public <T> Result unfreeze(Class<T> classOfT, Long id) {
        return unfreeze(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result unfreeze(Class<T> classOfT, String key, Object keyValue) {
        return freeze(classOfT, key, keyValue, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result unfreeze(Class<T> classOfT, Long id, Long userId, String userName) {
        return freeze(classOfT, "id", id, null, userId, userName);
    }

    public <T> Result unfreeze(Class<T> classOfT, Long id, String parKey, Long userId, String userName) {
        return freeze(classOfT, "id", id, parKey, userId, userName);
    }

    public <T> Result unfreeze(Class<T> classOfT, String key, Object keyValue, String parKey, Long userId, String userName) {
        return remove(classOfT, key, keyValue, StaticParams.STATE_UNFREEZE, parKey, userId, userName);
    }

    // 停用
    public <T> Result disable(Class<T> classOfT, Long id) {
        return disable(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result disable(Class<T> classOfT, String key, Object keyValue) {
        return freeze(classOfT, key, keyValue, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result disable(Class<T> classOfT, Long id, Long userId, String userName) {
        return disable(classOfT, "id", id, null, userId, userName);
    }

    public <T> Result disable(Class<T> classOfT, Long id, String parKey, Long userId, String userName) {
        return disable(classOfT, "id", id, parKey, userId, userName);
    }

    public <T> Result disable(Class<T> classOfT, String key, Object keyValue, String parKey, Long userId, String userName) {
        return remove(classOfT, key, keyValue, StaticParams.STATE_DISABLE, parKey, userId, userName);
    }

    // 启用，恢复使用
    public <T> Result enable(Class<T> classOfT, Long id) {
        return enable(classOfT, "id", id, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result enable(Class<T> classOfT, String key, Object keyValue) {
        return freeze(classOfT, key, keyValue, null, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result enable(Class<T> classOfT, Long id, Long userId, String userName) {
        return enable(classOfT, "id", id, null, userId, userName);
    }

    public <T> Result enable(Class<T> classOfT, Long id, String parKey, Long userId, String userName) {
        return enable(classOfT, "id", id, parKey, userId, userName);
    }

    public <T> Result enable(Class<T> classOfT, String key, Object keyValue, String parKey, Long userId, String userName) {
        return remove(classOfT, key, keyValue, StaticParams.STATE_ENABLE, parKey, userId, userName);
    }

    // 启动/停止（一般需要额外的业务逻辑）
    public <T> Result startOrStop(Class<T> classOfT, Long id, int isStart) {
        return startOrStop(classOfT, "id", id, isStart, Web.Util.getSessionUserId(request), Web.Util.getSessionUserName(request));
    }

    public <T> Result startOrStop(Class<T> classOfT, Long id, int isStart, Long userId, String userName) {
        return startOrStop(classOfT, "id", id, isStart, userId, userName);
    }

    public <T> Result startOrStop(Class<T> classOfT, String key, Object keyValue, int isStart, Long userId, String userName) {
        Result result = new Result();
        T t;
        Boolean flag = false;
        String operateName = "停止";
        String extendMsg = "";
        String modelShowName = "";
        if (isStart == 1) {
            operateName = "启动";
        } else {
            isStart = 0;
        }
        try {
            t = classOfT.newInstance();
            modelShowName = AnnotationUtil.getModelShowName(t); // model展示名称
            ModelUtil.setModelValue(t, key, keyValue);
            ModelUtil.setModelValue(t, StaticParams.DB_FILED_ISSTART, isStart);
            setUpdateInfo(t, userId, userName);

            Result extendResult = extendBeforeStartOrStop(classOfT, key, keyValue, isStart);
            if (extendResult.getSuccess()) {
                flag = getBaseDAO().update(t, key);
            } else {
                extendMsg = extendResult.getMessage();
            }
        } catch (Exception e) {
            flag = false;
            result.setMessage(e.getMessage());
            extendMsg += e.getMessage();
            log.error("", e);
        }
        if (flag) {
            return Web.Response.success(operateName + modelShowName + "成功！", key + ":" + keyValue);
        } else {
            return Web.Response.error(operateName + modelShowName + "失败！" + extendMsg);
        }
    }

    // 执行数据库操作前的业务处理
    public <T> Result extendBeforeStartOrStop(Class<T> classOfT, String key, Object keyValue, int isStart) {
        return Web.Response.success("");
    }

    // 执行sql语句
    public <T> Result execSql(String sql, Object... params) {
        boolean flag = false;
        String msg = "";
        try {
            flag = getBaseDAO().execSql(sql, params);
            if (flag) {
                Result result = extendAfterExecSql(flag, sql);
                flag = result.getSuccess();
                msg = result.getMessage();
            }
        } catch (Exception e) {
            log.error("执行sql出错！", e);
            String errMsg = e.getMessage();
            if (errMsg.contains("already exists Query")) { // Table 'test' already exists Query: CREATE TABLE……
                errMsg = "表 " + StringUtils.substringBetween(errMsg, "Table '", "' already exists") + " 已经存在！";
            }
            return Web.Response.error(errMsg);
        }
        if (flag) {
            return Web.Response.success("执行成功！");
        } else {
            return Web.Response.error(msg);
        }
    }

    // 执行sql语句
    public <T> Result addOne(Class<T> classOfT, Object idVal, String key) {
        return addOne(classOfT, idVal, key, null, null);
    }

    public <T> Result addOne(Class<T> classOfT, Object idVal, String key, Long userId, String userName) {
        return addNumber(classOfT, "id", idVal, key, 1, userId, userName);
    }

    /**
     * 数字添加，不记录更新人，如果要更新调用 {@link BasicService#addNumber(Class, Object, String, Number, Long, String)}
     * 
     * @Title addNumber
     * @author 吕凯
     * @date 2021年1月11日 下午2:00:33
     * @param <T>
     * @param classOfT
     * @param idVal
     * @param key
     * @param num
     * @return Result
     */
    public <T> Result addNumber(Class<T> classOfT, Object idVal, String key, Number num) {
        return addNumber(classOfT, idVal, key, num, null, null);
    }

    /**
     * 
     * 数字添加并记录更新人
     * 
     * @Title addNumber
     * @author 吕凯
     * @date 2021年1月11日 下午2:02:22
     * @param <T>
     * @param classOfT
     * @param idVal
     * @param key
     * @param num
     * @param userId
     * @param userName
     * @return Result
     */
    public <T> Result addNumber(Class<T> classOfT, Object idVal, String key, Number num, Long userId, String userName) {
        return addNumber(classOfT, "id", idVal, key, num, userId, userName);
    }

    public <T> Result addNumber(Class<T> classOfT, String pkName, Object pkVal, String key, Number num, Long userId, String userName) {
        String tableName = getBaseDAO().getTableName(classOfT);
        String sql = "UPDATE " + tableName + " SET " + key + "=" + key + "+" + num; // 负数也可，如+-1表示减1，mysql与oracle已测试
        List<Object> paramsList = new ArrayList<>();

        sql = setUpdateInfo(classOfT, userId, userName, sql, paramsList);
        sql += " WHERE " + pkName + "=?"; // 负数也可，如+-1表示减1，mysql与oracle已测试

        paramsList.add(pkVal);
        return execSql(sql, paramsList.toArray());
    }

    /**
     * 在sql中增加修改人信息
     * 
     * @Title setUpdateInfo
     * @author 吕凯
     * @date 2020年12月16日 上午9:00:52
     * @param <T>
     * @param classOfT
     * @param userId
     * @param userName
     * @param sql
     * @param paramsList
     * @return String
     */
    protected <T> String setUpdateInfo(Class<T> classOfT, Long userId, String userName, String sql, List<Object> paramsList) {
        if (AnnotationUtil.hasAndNotOnlyshowField(classOfT, StaticParams.DB_FILED_UPDATE_BY)) { // 存在并且不是只展示字段
            if (userId != null && userId != 0L) {
                sql += "," + StaticParams.DB_FILED_UPDATE_BY + "=?";
                paramsList.add(userId);
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(classOfT, StaticParams.DB_FILED_UPDATE_NAME)) { // 修改人姓名
            if (StringUtils.isNotEmpty(userName)) {
                sql += "," + StaticParams.DB_FILED_UPDATE_NAME + "=?";
                paramsList.add(userName);
            }
        }
        if (AnnotationUtil.hasAndNotOnlyshowField(classOfT, StaticParams.DB_FILED_UPDATE_TIME)) {
            if (userId != null && userId != 0L) {
                sql += "," + StaticParams.DB_FILED_UPDATE_TIME + "=?";
                paramsList.add(new Date());
            }
        }
        return sql;
    }

    // 执行数据库操作前的业务处理
    public <T> Result extendAfterExecSql(boolean flag, String sql) {
        return Web.Response.success("");
    }

    /**
     * 获取state不为-1的QueryModel（需要有state字段）
     *
     * @Title getValidQueryModel
     * @author 吕凯
     * @date 2018年12月18日 下午4:36:49
     * @return QueryModel
     */
    public QueryModel getValidQueryModel() {
        QueryModel queryModel = getQueryModel();
        queryModel.addUnEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_DELETE);
        return queryModel;
    }

    /**
     * 获取一个空条件的QueryModel
     *
     * @Title getValidQueryModel
     * @author 吕凯
     * @date 2018年12月18日 下午4:36:49
     * @return QueryModel
     */
    public QueryModel getQueryModel() {
        return getQueryModel(null);
    }

    /**
     * 获取选中参数的queryModel
     * 
     * @Title getQueryModel
     * @author 吕凯
     * @date 2021年6月3日 下午4:35:40
     * @param selectFields
     * @return QueryModel
     */
    public QueryModel getQueryModel(String selectFields) {
        QueryModel queryModel = null;
        if (StringUtils.isNotEmpty(selectFields)) {
            queryModel = new QueryModel(selectFields);
        } else {
            queryModel = new QueryModel();
        }
        return queryModel;
    }

    /**
     * 获取状态为正常的QueryModel（需要有state字段）
     *
     * @Title getNormalQueryModel
     * @author 吕凯
     * @date 2018年12月18日 下午4:36:13
     * @return QueryModel
     */
    public QueryModel getNormalQueryModel() {
        return getNormalQueryModel(null);
    }

    /**
     * 获取状态为正常的QueryModel（需要有state字段）并制定返回字段
     * 
     * @Title getNormalQueryModel
     * @author 吕凯
     * @date 2020年11月30日 下午5:37:53
     * @param selectFields
     * @return QueryModel
     */
    public QueryModel getNormalQueryModel(String selectFields) {
        QueryModel queryModel = null;
        if (StringUtils.isNotEmpty(selectFields)) {
            queryModel = new QueryModel(selectFields);
        } else {
            queryModel = new QueryModel();
        }
        queryModel.addEq(StaticParams.DB_FILED_STATE, StaticParams.STATE_NORMAL);
        return queryModel;
    }

    /**
     *
     * 关联查询queryModel
     *
     * @Title getLinkSearchQueryModel
     * @author 刘金浩
     * @date 2019年10月10日 下午1:15:10
     * @param request
     * @param classOfT
     * @param property
     * @return QueryModel
     */
    public <T> QueryModel getLinkSearchQueryModel(HttpServletRequest request, Class<T> classOfT, Property<T, ?> property) {
        QueryModel linkedQueryModel = new QueryModel(); // 另一个关联表
        String fieldName = FunctionUtil.getFieldName(property);
        Field field = ModelUtil.getField(classOfT, fieldName);
        Class<?> peopertyClazz = ClassUtil.getFieldPojoType(field);
        Web.Parameter.dealReqParams(request, peopertyClazz, linkedQueryModel, fieldName);
        return linkedQueryModel;
    }

    /**
     * 获取设置为启动的对象（一般为任务、监听器等）
     *
     * @Title getIsStart
     * @author 吕凯
     * @date 2019年3月2日 上午9:21:50
     * @param classOfT
     * @return List<T>
     */
    public <T> List<T> getIsStartList(Class<T> classOfT) {
        return getIsStartList(classOfT, null);
    }

    /**
     * 获取设置为启动的对象（一般为任务、监听器等）
     *
     * @Title getStartTask
     * @author 吕凯
     * @date 2019年3月2日 上午9:11:34
     * @param size
     * @return List<SysTimedtaskModel>
     */
    public <T> List<T> getIsStartList(Class<T> classOfT, Integer size) {
        // 查询启动的任务
        QueryModel queryModel = new QueryModel();
        queryModel.addEq("isStart", 1); // 启动
        queryModel.addEq("state", StaticParams.STATE_NORMAL);
        queryModel.setOrder("createTime", true); // 默认按时间倒序排列
        List<T> modelList = null;
        if (size != null) {
            modelList = getList(classOfT, queryModel, size);
        } else {
            modelList = getList(classOfT, queryModel);
        }
        return modelList;
    }

    /**
     * 根据id判断是否存在
     *
     * @Title existById
     * @author 吕凯
     * @date 2019年4月17日 下午1:27:31
     * @param classOfT
     * @param idValue
     * @return boolean
     */
    public <T> boolean existById(Class<T> classOfT, Object idValue) {
        return exist(classOfT, "id", idValue);
    }

    /**
     * 判断是存在id为ldValue的数据
     * 
     * @Title exist
     * @author 吕凯
     * @date 2020年4月18日 上午10:48:11
     * @param classOfT
     * @param ldValue
     * @return boolean
     */
    public <T> boolean exist(Class<T> classOfT, Object ldValue) {
        return getBaseDAO().exists(classOfT, "id", ldValue);
    }

    /**
     * 判断是否存在
     *
     * @Title exist
     * @author 吕凯
     * @date 2019年4月17日 下午1:27:21
     * @param classOfT
     * @param key
     * @param value
     * @return boolean
     */
    public <T> boolean exist(Class<T> classOfT, String key, Object value) {
        return getBaseDAO().exists(classOfT, key, value);
    }

    public TransactionImplBaseDao getBaseDAO() {
        if (BaseDAO == null) {
            DataSource dataSource = this.getClass().getAnnotation(DataSource.class);
            String dataSourceValue = defaultDataSource; // 默认值
            if (dataSource != null && StringUtils.isNotBlank(dataSource.value())) {
                dataSourceValue = dataSource.value();
            }
            log.debug("dataSource==" + dataSourceValue + " " + this.getClass());
            BaseDAO = (TransactionImplBaseDao) DaoFactory.getDao(dataSourceValue);
        }
        return BaseDAO;
    }

    /**
     * 下载文件
     *
     * @Title downFile
     * @author 吕凯
     * @date 2019年5月9日 上午8:41:21
     * @param file
     * @return ResponseEntity<FileSystemResource>
     */
    public ResponseEntity<FileSystemResource> downFile(File file) {
        // 参考https://blog.csdn.net/qq_33392133/article/details/78662439
        if (file == null) {
            return null;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + file.getName());
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        return ResponseEntity.ok().headers(headers).contentLength(file.length())
                .contentType(MediaType.parseMediaType("application/octet-stream")).body(new FileSystemResource(file));
    }

    public DBTabelService getDBService() {
        DBSetInfo dbSetInfo = new DBSetInfo();
        dbSetInfo.setDbUrl(PropertiesModel.CONFIG.getString("db0.url"));
        dbSetInfo.setDbUserName(PropertiesModel.CONFIG.getString("db0.username"));
        dbSetInfo.setDbPassword(PropertiesModel.CONFIG.getString("db0.password"));
        DBTabelService service = DBTabelService.getInstance(dbSetInfo);
        return service;
    }

    /**
     *
     * 检查表是否存在
     *
     * @Title checkTable
     * @author 吕凯
     * @date 2019年11月1日 上午7:45:12
     * @return Result
     */
    public Result checkTable(String tableName) {
        DBTabelService service = getDBService();
        Result tableResult = service.checkTableExist(tableName);
        if (!tableResult.getSuccess()) { // 表不存在，需要先创建
            return Web.Response.error("表" + tableName + "不存在！");
        }
        return Web.Response.success("表存在！");
    }

    /**
     *
     * 根据文件创建表
     *
     * @Title createTable
     * @author 吕凯
     * @date 2019年11月1日 上午7:48:00
     * @param filePath
     *            sql文件相对classes的路径
     * @return Result
     */
    public Result createTable(String filePath) {
        String sql = getFileContent(filePath).trim();
        if (StringUtils.isEmpty(sql)) {
            return Web.Response.error("建表语句不能正确读取！");
        }
        DBTabelService service = getDBService();
        Result result = execSql(service.getDAO(), sql);
        if (!result.getSuccess()) {
            return Web.Response.error("建表失败！" + result.getMessage());
        }
        return Web.Response.success("建表完成，请到数据库中检查是否正确！");
    }

    /**
     * 获取文件内容
     *
     * @Title getCreateTableSql
     * @author 吕凯
     * @date 2019年11月1日 上午7:47:30
     * @param filePath
     * @return String
     */
    public String getFileContent(String filePath) {
        StringBuilder sb = new StringBuilder("");
        try {
            InputStream inputStream = IOUtils.readAsInputStream(filePath, false);
//            URL resourceURL = this.getClass().getClassLoader().getResource(filePath);
            if (inputStream != null) {
                List<String> lines = IOUtils.readLines(inputStream, "UTF-8");
//                List<String> lines = IOUtils.readLines(resourceURL.openStream(), "UTF-8");
                lines.stream().forEach(line -> sb.append(line).append("\n"));
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return sb.toString();
    }

    /**
     * 执行sql语句
     *
     * @Title execSql
     * @author 吕凯
     * @date 2019年11月1日 上午7:47:14
     * @param DAO
     * @param sql
     * @param params
     * @return Result
     */
    public Result execSql(DynamicBaseDao DAO, String sql, Object... params) {
        boolean flag = false;
        String msg = "";
        try {
            flag = DAO.execSql(sql, params);
            if (flag) {
                Result result = extendAfterExecSql(flag, sql);
                flag = result.getSuccess();
                msg = result.getMessage();
            }
        } catch (Exception e) {
            log.error("执行sql出错！", e);
            String errMsg = e.getMessage();
            if (errMsg.contains("already exists Query")) { // Table 'test' already exists Query: CREATE TABLE……
                errMsg = "表 " + StringUtils.substringBetween(errMsg, "Table '", "' already exists") + " 已经存在！";
            }
            return Web.Response.error(errMsg);
        }
        if (flag) {
            return Web.Response.success("执行成功！");
        } else {
            return Web.Response.error(msg);
        }
    }

}
